Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/comdlg32/finddlg.c
4388 views
1
/*
2
* Common Dialog Boxes interface (32 bit)
3
* Find/Replace
4
*
5
* Copyright 1998,1999 Bertho A. Stultiens
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 <stdarg.h>
23
#include <string.h>
24
#include "windef.h"
25
#include "winbase.h"
26
#include "winnls.h"
27
#include "wingdi.h"
28
#include "winuser.h"
29
#include "commdlg.h"
30
#include "cderr.h"
31
#include "dlgs.h"
32
#include "wine/debug.h"
33
#include "wine/heap.h"
34
35
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
36
37
#include "cdlg.h"
38
39
40
/*-----------------------------------------------------------------------*/
41
42
static UINT FindReplaceMessage;
43
static UINT HelpMessage;
44
45
#define FR_MASK (FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD | FR_REPLACEALL | FR_REPLACE | FR_FINDNEXT | FR_DIALOGTERM)
46
/* CRITICAL_SECTION COMDLG32_CritSect; */
47
48
/* Notes:
49
* MS uses a critical section at a few locations. However, I fail to
50
* see the reason for this. Their comdlg32.dll has a few race conditions
51
* but _not_ at those places that are protected with the mutex (there are
52
* globals that seem to hold info for the wndproc).
53
*
54
* FindText[AW]/ReplaceText[AW]
55
* The find/replace calls are passed a structure that is _not_ used
56
* internally. There is a local copy that holds the running info to
57
* be able to combine xxxA and xxxW calls. The passed pointer is
58
* returned upon sendmessage. Apps won't break this way when they rely
59
* on the original pointer. This will work as long as the sizes of
60
* FINDREPLACEA == FINDREPLACEW. The local copy will also prevent
61
* the app to see the wine-specific extra flags to distinguish between
62
* A/W and Find/Replace.
63
*/
64
65
66
/***********************************************************************
67
* COMDLG32_FR_GetFlags [internal]
68
* Returns the button state that needs to be reported to the caller.
69
* RETURNS
70
* Current state of check and radio buttons
71
*/
72
static DWORD COMDLG32_FR_GetFlags(HWND hDlgWnd)
73
{
74
DWORD flags = 0;
75
if(IsDlgButtonChecked(hDlgWnd, rad2) == BST_CHECKED)
76
flags |= FR_DOWN;
77
if(IsDlgButtonChecked(hDlgWnd, chx1) == BST_CHECKED)
78
flags |= FR_WHOLEWORD;
79
if(IsDlgButtonChecked(hDlgWnd, chx2) == BST_CHECKED)
80
flags |= FR_MATCHCASE;
81
return flags;
82
}
83
84
/***********************************************************************
85
* COMDLG32_FR_HandleWMCommand [internal]
86
* Handle WM_COMMAND messages...
87
*/
88
static void COMDLG32_FR_HandleWMCommand(HWND hDlgWnd, COMDLG32_FR_Data *pData, int Id, int NotifyCode)
89
{
90
DWORD flag;
91
92
pData->user_fr.fra->Flags &= ~FR_MASK; /* Clear return flags */
93
if(pData->fr.Flags & FR_WINE_REPLACE) /* Replace always goes down... */
94
pData->user_fr.fra->Flags |= FR_DOWN;
95
96
if(NotifyCode == BN_CLICKED)
97
{
98
switch(Id)
99
{
100
case IDOK: /* Find Next */
101
if(GetDlgItemTextA(hDlgWnd, edt1, pData->fr.lpstrFindWhat, pData->fr.wFindWhatLen) > 0)
102
{
103
pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | FR_FINDNEXT;
104
if(pData->fr.Flags & FR_WINE_UNICODE)
105
{
106
MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrFindWhat, -1,
107
pData->user_fr.frw->lpstrFindWhat,
108
0x7fffffff );
109
}
110
else
111
{
112
strcpy(pData->user_fr.fra->lpstrFindWhat, pData->fr.lpstrFindWhat);
113
}
114
SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra);
115
}
116
break;
117
118
case IDCANCEL:
119
pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | FR_DIALOGTERM;
120
SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra);
121
DestroyWindow(hDlgWnd);
122
break;
123
124
case psh2: /* Replace All */
125
flag = FR_REPLACEALL;
126
goto Replace;
127
128
case psh1: /* Replace */
129
flag = FR_REPLACE;
130
Replace:
131
if((pData->fr.Flags & FR_WINE_REPLACE)
132
&& GetDlgItemTextA(hDlgWnd, edt1, pData->fr.lpstrFindWhat, pData->fr.wFindWhatLen) > 0)
133
{
134
pData->fr.lpstrReplaceWith[0] = 0; /* In case the next GetDlgItemText Fails */
135
GetDlgItemTextA(hDlgWnd, edt2, pData->fr.lpstrReplaceWith, pData->fr.wReplaceWithLen);
136
pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | flag;
137
if(pData->fr.Flags & FR_WINE_UNICODE)
138
{
139
MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrFindWhat, -1,
140
pData->user_fr.frw->lpstrFindWhat,
141
0x7fffffff );
142
MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrReplaceWith, -1,
143
pData->user_fr.frw->lpstrReplaceWith,
144
0x7fffffff );
145
}
146
else
147
{
148
strcpy(pData->user_fr.fra->lpstrFindWhat, pData->fr.lpstrFindWhat);
149
strcpy(pData->user_fr.fra->lpstrReplaceWith, pData->fr.lpstrReplaceWith);
150
}
151
SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra);
152
}
153
break;
154
155
case pshHelp:
156
pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd);
157
SendMessageA(pData->fr.hwndOwner, HelpMessage, (WPARAM)hDlgWnd, (LPARAM)pData->user_fr.fra);
158
break;
159
}
160
}
161
else if(NotifyCode == EN_CHANGE && Id == edt1)
162
{
163
BOOL enable = SendDlgItemMessageA(hDlgWnd, edt1, WM_GETTEXTLENGTH, 0, 0) > 0;
164
EnableWindow(GetDlgItem(hDlgWnd, IDOK), enable);
165
if(pData->fr.Flags & FR_WINE_REPLACE)
166
{
167
EnableWindow(GetDlgItem(hDlgWnd, psh1), enable);
168
EnableWindow(GetDlgItem(hDlgWnd, psh2), enable);
169
}
170
}
171
}
172
173
/***********************************************************************
174
* COMDLG32_FindReplaceDlgProc [internal]
175
* [Find/Replace]Text32[A/W] window procedure.
176
*/
177
static INT_PTR CALLBACK COMDLG32_FindReplaceDlgProc(HWND hDlgWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
178
{
179
COMDLG32_FR_Data *pdata = GetPropA(hDlgWnd, (LPSTR)COMDLG32_Atom);
180
INT_PTR retval = TRUE;
181
182
if(iMsg == WM_INITDIALOG)
183
{
184
pdata = (COMDLG32_FR_Data *)lParam;
185
if(!SetPropA(hDlgWnd, (LPSTR)COMDLG32_Atom, (HANDLE)pdata))
186
{
187
ERR("Could not Set prop; invent a graceful exit?...\n");
188
DestroyWindow(hDlgWnd);
189
return FALSE;
190
}
191
SendDlgItemMessageA(hDlgWnd, edt1, EM_SETLIMITTEXT, pdata->fr.wFindWhatLen, 0);
192
SendDlgItemMessageA(hDlgWnd, edt1, WM_SETTEXT, 0, (LPARAM)pdata->fr.lpstrFindWhat);
193
if(pdata->fr.Flags & FR_WINE_REPLACE)
194
{
195
SendDlgItemMessageA(hDlgWnd, edt2, EM_SETLIMITTEXT, pdata->fr.wReplaceWithLen, 0);
196
SendDlgItemMessageA(hDlgWnd, edt2, WM_SETTEXT, 0, (LPARAM)pdata->fr.lpstrReplaceWith);
197
}
198
199
if(!(pdata->fr.Flags & FR_SHOWHELP))
200
ShowWindow(GetDlgItem(hDlgWnd, pshHelp), SW_HIDE);
201
if(pdata->fr.Flags & FR_HIDEUPDOWN)
202
{
203
ShowWindow(GetDlgItem(hDlgWnd, rad1), SW_HIDE);
204
ShowWindow(GetDlgItem(hDlgWnd, rad2), SW_HIDE);
205
ShowWindow(GetDlgItem(hDlgWnd, grp1), SW_HIDE);
206
}
207
else if(pdata->fr.Flags & FR_NOUPDOWN)
208
{
209
EnableWindow(GetDlgItem(hDlgWnd, rad1), FALSE);
210
EnableWindow(GetDlgItem(hDlgWnd, rad2), FALSE);
211
EnableWindow(GetDlgItem(hDlgWnd, grp1), FALSE);
212
}
213
else
214
{
215
SendDlgItemMessageA(hDlgWnd, rad1, BM_SETCHECK, pdata->fr.Flags & FR_DOWN ? 0 : BST_CHECKED, 0);
216
SendDlgItemMessageA(hDlgWnd, rad2, BM_SETCHECK, pdata->fr.Flags & FR_DOWN ? BST_CHECKED : 0, 0);
217
}
218
219
if(pdata->fr.Flags & FR_HIDEMATCHCASE)
220
ShowWindow(GetDlgItem(hDlgWnd, chx2), SW_HIDE);
221
else if(pdata->fr.Flags & FR_NOMATCHCASE)
222
EnableWindow(GetDlgItem(hDlgWnd, chx2), FALSE);
223
else
224
SendDlgItemMessageA(hDlgWnd, chx2, BM_SETCHECK, pdata->fr.Flags & FR_MATCHCASE ? BST_CHECKED : 0, 0);
225
226
if(pdata->fr.Flags & FR_HIDEWHOLEWORD)
227
ShowWindow(GetDlgItem(hDlgWnd, chx1), SW_HIDE);
228
else if(pdata->fr.Flags & FR_NOWHOLEWORD)
229
EnableWindow(GetDlgItem(hDlgWnd, chx1), FALSE);
230
else
231
SendDlgItemMessageA(hDlgWnd, chx1, BM_SETCHECK, pdata->fr.Flags & FR_WHOLEWORD ? BST_CHECKED : 0, 0);
232
233
/* We did the init here, now call the hook if requested */
234
235
/* We do not do ShowWindow if hook exists and is FALSE */
236
/* per MSDN Article Q96135 */
237
if((pdata->fr.Flags & FR_ENABLEHOOK)
238
&& ! pdata->fr.lpfnHook(hDlgWnd, iMsg, wParam, (LPARAM) &pdata->fr))
239
return TRUE;
240
ShowWindow(hDlgWnd, SW_SHOWNORMAL);
241
UpdateWindow(hDlgWnd);
242
return TRUE;
243
}
244
245
if(pdata && (pdata->fr.Flags & FR_ENABLEHOOK))
246
{
247
retval = pdata->fr.lpfnHook(hDlgWnd, iMsg, wParam, lParam);
248
}
249
else
250
retval = FALSE;
251
252
if(pdata && !retval)
253
{
254
retval = TRUE;
255
switch(iMsg)
256
{
257
case WM_COMMAND:
258
COMDLG32_FR_HandleWMCommand(hDlgWnd, pdata, LOWORD(wParam), HIWORD(wParam));
259
break;
260
261
case WM_CLOSE:
262
COMDLG32_FR_HandleWMCommand(hDlgWnd, pdata, IDCANCEL, BN_CLICKED);
263
break;
264
265
case WM_HELP:
266
/* Heeeeelp! */
267
FIXME("Got WM_HELP. Who is gonna supply it?\n");
268
break;
269
270
case WM_CONTEXTMENU:
271
/* Heeeeelp! */
272
FIXME("Got WM_CONTEXTMENU. Who is gonna supply it?\n");
273
break;
274
/* FIXME: Handle F1 help */
275
276
default:
277
retval = FALSE; /* We did not handle the message */
278
}
279
}
280
281
/* WM_DESTROY is a special case.
282
* We need to ensure that the allocated memory is freed just before
283
* the dialog is killed. We also need to remove the added prop.
284
*/
285
if(iMsg == WM_DESTROY)
286
{
287
RemovePropA(hDlgWnd, (LPSTR)COMDLG32_Atom);
288
heap_free(pdata);
289
}
290
291
return retval;
292
}
293
294
/***********************************************************************
295
* COMDLG32_FR_CheckPartial [internal]
296
* Check various fault conditions in the supplied parameters that
297
* cause an extended error to be reported.
298
* RETURNS
299
* TRUE: Success
300
* FALSE: Failure
301
*/
302
static BOOL COMDLG32_FR_CheckPartial(
303
const FINDREPLACEA *pfr, /* [in] Find structure */
304
BOOL Replace /* [in] True if called as replace */
305
) {
306
if(!pfr)
307
{
308
COMDLG32_SetCommDlgExtendedError(CDERR_INITIALIZATION);
309
return FALSE;
310
}
311
312
if(pfr->lStructSize != sizeof(FINDREPLACEA))
313
{
314
COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE);
315
return FALSE;
316
}
317
318
if(!IsWindow(pfr->hwndOwner))
319
{
320
COMDLG32_SetCommDlgExtendedError(CDERR_DIALOGFAILURE);
321
return FALSE;
322
}
323
324
if((pfr->wFindWhatLen < 1 || !pfr->lpstrFindWhat)
325
||(Replace && !pfr->lpstrReplaceWith))
326
{
327
COMDLG32_SetCommDlgExtendedError(FRERR_BUFFERLENGTHZERO);
328
return FALSE;
329
}
330
331
if((FindReplaceMessage = RegisterWindowMessageA(FINDMSGSTRINGA)) == 0)
332
{
333
COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL);
334
return FALSE;
335
}
336
if((HelpMessage = RegisterWindowMessageA(HELPMSGSTRINGA)) == 0)
337
{
338
COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL);
339
return FALSE;
340
}
341
342
if((pfr->Flags & FR_ENABLEHOOK) && !pfr->lpfnHook)
343
{
344
COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK);
345
return FALSE;
346
}
347
348
if((pfr->Flags & FR_ENABLETEMPLATEHANDLE) && !pfr->hInstance)
349
{
350
COMDLG32_SetCommDlgExtendedError(CDERR_NOHINSTANCE);
351
return FALSE;
352
}
353
354
return TRUE;
355
}
356
357
/***********************************************************************
358
* COMDLG32_FR_DoFindReplace [internal]
359
* Actual load and creation of the Find/Replace dialog.
360
* RETURNS
361
* Window handle to created dialog:Success
362
* NULL:Failure
363
*/
364
static HWND COMDLG32_FR_DoFindReplace(
365
COMDLG32_FR_Data *pdata /* [in] Internal data structure */
366
) {
367
HWND hdlgwnd = 0;
368
HGLOBAL loadrc;
369
DWORD error;
370
LPDLGTEMPLATEW rcs;
371
372
TRACE("hInst=%p, Flags=%08lx\n", pdata->fr.hInstance, pdata->fr.Flags);
373
374
if(!(pdata->fr.Flags & FR_ENABLETEMPLATEHANDLE))
375
{
376
HMODULE hmod = COMDLG32_hInstance;
377
HRSRC htemplate;
378
if(pdata->fr.Flags & FR_ENABLETEMPLATE)
379
{
380
hmod = pdata->fr.hInstance;
381
if(pdata->fr.Flags & FR_WINE_UNICODE)
382
{
383
htemplate = FindResourceW(hmod, (LPCWSTR)pdata->fr.lpTemplateName, (LPWSTR)RT_DIALOG);
384
}
385
else
386
{
387
htemplate = FindResourceA(hmod, pdata->fr.lpTemplateName, (LPCSTR)RT_DIALOG);
388
}
389
}
390
else
391
{
392
int rcid = pdata->fr.Flags & FR_WINE_REPLACE ? REPLACEDLGORD
393
: FINDDLGORD;
394
htemplate = FindResourceA(hmod, MAKEINTRESOURCEA(rcid), (LPCSTR)RT_DIALOG);
395
}
396
if(!htemplate)
397
{
398
error = CDERR_FINDRESFAILURE;
399
goto cleanup;
400
}
401
402
loadrc = LoadResource(hmod, htemplate);
403
}
404
else
405
{
406
loadrc = pdata->fr.hInstance;
407
}
408
409
if(!loadrc)
410
{
411
error = CDERR_LOADRESFAILURE;
412
goto cleanup;
413
}
414
415
if((rcs = LockResource(loadrc)) == NULL)
416
{
417
error = CDERR_LOCKRESFAILURE;
418
goto cleanup;
419
}
420
421
hdlgwnd = CreateDialogIndirectParamA(COMDLG32_hInstance,
422
rcs,
423
pdata->fr.hwndOwner,
424
COMDLG32_FindReplaceDlgProc,
425
(LPARAM)pdata);
426
if(!hdlgwnd)
427
{
428
error = CDERR_DIALOGFAILURE;
429
cleanup:
430
COMDLG32_SetCommDlgExtendedError(error);
431
heap_free(pdata);
432
}
433
return hdlgwnd;
434
}
435
436
/***********************************************************************
437
* FindTextA [COMDLG32.@]
438
*
439
* See FindTextW.
440
*/
441
HWND WINAPI FindTextA(
442
LPFINDREPLACEA pfr /* [in] Find/replace structure*/
443
) {
444
COMDLG32_FR_Data *pdata;
445
446
TRACE("LPFINDREPLACE=%p\n", pfr);
447
448
if(!COMDLG32_FR_CheckPartial(pfr, FALSE))
449
return 0;
450
451
if((pdata = COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data))) == NULL)
452
return 0; /* Error has been set */
453
454
pdata->user_fr.fra = pfr;
455
pdata->fr = *pfr;
456
return COMDLG32_FR_DoFindReplace(pdata);
457
}
458
459
/***********************************************************************
460
* ReplaceTextA [COMDLG32.@]
461
*
462
* See ReplaceTextW.
463
*/
464
HWND WINAPI ReplaceTextA(
465
LPFINDREPLACEA pfr /* [in] Find/replace structure*/
466
) {
467
COMDLG32_FR_Data *pdata;
468
469
TRACE("LPFINDREPLACE=%p\n", pfr);
470
471
if(!COMDLG32_FR_CheckPartial(pfr, TRUE))
472
return 0;
473
474
if((pdata = COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data))) == NULL)
475
return 0; /* Error has been set */
476
477
pdata->user_fr.fra = pfr;
478
pdata->fr = *pfr;
479
pdata->fr.Flags |= FR_WINE_REPLACE;
480
return COMDLG32_FR_DoFindReplace(pdata);
481
}
482
483
/***********************************************************************
484
* FindTextW [COMDLG32.@]
485
*
486
* Create a modeless find-text dialog box.
487
*
488
* RETURNS
489
* Window handle to created dialog: Success
490
* NULL: Failure
491
*/
492
HWND WINAPI FindTextW(
493
LPFINDREPLACEW pfr /* [in] Find/replace structure*/
494
) {
495
COMDLG32_FR_Data *pdata;
496
DWORD len;
497
498
TRACE("LPFINDREPLACE=%p\n", pfr);
499
500
if(!COMDLG32_FR_CheckPartial((LPFINDREPLACEA)pfr, FALSE))
501
return 0;
502
503
len = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen,
504
NULL, 0, NULL, NULL );
505
if((pdata = COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data) + len)) == NULL)
506
return 0; /* Error has been set */
507
508
pdata->user_fr.frw = pfr;
509
pdata->fr = *(LPFINDREPLACEA)pfr; /* FINDREPLACEx have same size */
510
pdata->fr.Flags |= FR_WINE_UNICODE;
511
pdata->fr.lpstrFindWhat = (LPSTR)(pdata + 1); /* Set string pointer */
512
WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen,
513
pdata->fr.lpstrFindWhat, len, NULL, NULL );
514
return COMDLG32_FR_DoFindReplace(pdata);
515
}
516
517
/***********************************************************************
518
* ReplaceTextW [COMDLG32.@]
519
*
520
* Create a modeless replace-text dialog box.
521
*
522
* RETURNS
523
* Window handle to created dialog: Success
524
* NULL: Failure
525
*/
526
HWND WINAPI ReplaceTextW(
527
LPFINDREPLACEW pfr /* [in] Find/replace structure*/
528
) {
529
COMDLG32_FR_Data *pdata;
530
DWORD len1, len2;
531
532
TRACE("LPFINDREPLACE=%p\n", pfr);
533
534
if(!COMDLG32_FR_CheckPartial((LPFINDREPLACEA)pfr, TRUE))
535
return 0;
536
537
len1 = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen,
538
NULL, 0, NULL, NULL );
539
len2 = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrReplaceWith, pfr->wReplaceWithLen,
540
NULL, 0, NULL, NULL );
541
if((pdata = COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data) + len1 + len2)) == NULL)
542
return 0; /* Error has been set */
543
544
pdata->user_fr.frw = pfr;
545
pdata->fr = *(LPFINDREPLACEA)pfr; /* FINDREPLACEx have same size */
546
pdata->fr.Flags |= FR_WINE_REPLACE | FR_WINE_UNICODE;
547
pdata->fr.lpstrFindWhat = (LPSTR)(pdata + 1); /* Set string pointer */
548
pdata->fr.lpstrReplaceWith = pdata->fr.lpstrFindWhat + len1;
549
550
WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen,
551
pdata->fr.lpstrFindWhat, len1, NULL, NULL );
552
WideCharToMultiByte( CP_ACP, 0, pfr->lpstrReplaceWith, pfr->wReplaceWithLen,
553
pdata->fr.lpstrReplaceWith, len2, NULL, NULL );
554
return COMDLG32_FR_DoFindReplace(pdata);
555
}
556
557