comctl32undoc.c 34.5 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Undocumented functions from COMCTL32.DLL
 *
4
 * Copyright 1998 Eric Kohl
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *           1998 Juergen Schmied <j.schmied@metronet.de>
6 7
 *           2000 Eric Kohl for CodeWeavers
 *
8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
22 23 24 25 26 27 28
 * NOTES
 *     All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!!
 *     Do NOT rely on names or contents of undocumented structures and types!!!
 *     These functions are used by EXPLORER.EXE, IEXPLORE.EXE and
 *     COMCTL32.DLL (internally).
 *
 */
29 30
#include "config.h"
#include "wine/port.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
31

32
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
33 34
#include <string.h>
#include <ctype.h>
35
#include <limits.h>
36

37
#define COBJMACROS
38 39
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
40

41 42 43 44 45 46
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
47 48
#include "commctrl.h"
#include "objbase.h"
49
#include "winerror.h"
50

51
#include "wine/unicode.h"
52 53
#include "comctl32.h"

54
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
55

56
WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
57

58 59
static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 };

Alexandre Julliard's avatar
Alexandre Julliard committed
60 61 62
/**************************************************************************
 * Alloc [COMCTL32.71]
 *
63
 * Allocates memory block from the dll's private heap
Alexandre Julliard's avatar
Alexandre Julliard committed
64 65 66 67 68 69 70 71
 *
 * PARAMS
 *     dwSize [I] size of the allocated memory block
 *
 * RETURNS
 *     Success: pointer to allocated memory block
 *     Failure: NULL
 */
72
LPVOID WINAPI Alloc (DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
73
{
74
    return LocalAlloc( LMEM_ZEROINIT, dwSize );
Alexandre Julliard's avatar
Alexandre Julliard committed
75 76 77 78 79 80 81
}


/**************************************************************************
 * ReAlloc [COMCTL32.72]
 *
 * Changes the size of an allocated memory block or allocates a memory
82
 * block using the dll's private heap.
Alexandre Julliard's avatar
Alexandre Julliard committed
83 84 85 86 87 88 89 90 91 92
 *
 * PARAMS
 *     lpSrc  [I] pointer to memory block which will be resized
 *     dwSize [I] new size of the memory block.
 *
 * RETURNS
 *     Success: pointer to the resized memory block
 *     Failure: NULL
 *
 * NOTES
93 94
 *     If lpSrc is a NULL-pointer, then ReAlloc allocates a memory
 *     block like Alloc.
Alexandre Julliard's avatar
Alexandre Julliard committed
95
 */
96
LPVOID WINAPI ReAlloc (LPVOID lpSrc, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
97 98
{
    if (lpSrc)
99
        return LocalReAlloc( lpSrc, dwSize, LMEM_ZEROINIT );
Alexandre Julliard's avatar
Alexandre Julliard committed
100
    else
101
        return LocalAlloc( LMEM_ZEROINIT, dwSize);
Alexandre Julliard's avatar
Alexandre Julliard committed
102 103 104 105 106
}


/**************************************************************************
 * Free [COMCTL32.73]
107
 *
108
 * Frees an allocated memory block from the dll's private heap.
Alexandre Julliard's avatar
Alexandre Julliard committed
109 110 111 112 113 114 115 116
 *
 * PARAMS
 *     lpMem [I] pointer to memory block which will be freed
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */
117
BOOL WINAPI Free (LPVOID lpMem)
Alexandre Julliard's avatar
Alexandre Julliard committed
118
{
119
    return !LocalFree( lpMem );
Alexandre Julliard's avatar
Alexandre Julliard committed
120 121 122 123 124 125 126
}


/**************************************************************************
 * GetSize [COMCTL32.74]
 *
 * Retrieves the size of the specified memory block from the dll's
127
 * private heap.
Alexandre Julliard's avatar
Alexandre Julliard committed
128 129 130 131 132 133 134 135
 *
 * PARAMS
 *     lpMem [I] pointer to an allocated memory block
 *
 * RETURNS
 *     Success: size of the specified memory block
 *     Failure: 0
 */
136
DWORD WINAPI GetSize (LPVOID lpMem)
Alexandre Julliard's avatar
Alexandre Julliard committed
137
{
138
    return LocalSize( lpMem );
Alexandre Julliard's avatar
Alexandre Julliard committed
139 140 141
}


Alexandre Julliard's avatar
Alexandre Julliard committed
142
/**************************************************************************
143
 * MRU-Functions  {COMCTL32}
Alexandre Julliard's avatar
Alexandre Julliard committed
144
 *
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
 * NOTES
 * The MRU-Api is a set of functions to manipulate lists of M.R.U. (Most Recently
 * Used) items. It is an undocumented Api that is used (at least) by the shell
 * and explorer to implement their recent documents feature.
 *
 * Since these functions are undocumented, they are unsupported by MS and
 * may change at any time.
 *
 * Internally, the list is implemented as a last in, last out list of items
 * persisted into the system registry under a caller chosen key. Each list
 * item is given a one character identifier in the Ascii range from 'a' to
 * '}'. A list of the identifiers in order from newest to oldest is stored
 * under the same key in a value named "MRUList".
 *
 * Items are re-ordered by changing the order of the values in the MRUList
 * value. When a new item is added, it becomes the new value of the oldest
 * identifier, and that identifier is moved to the front of the MRUList value.
 * 
 * Wine stores MRU-lists in the same registry format as Windows, so when
 * switching between the builtin and native comctl32.dll no problems or
 * incompatibilities should occur.
 *
 * The following undocumented structure is used to create an MRU-list:
 *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs);
 *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
 *|
 *|typedef struct tagCREATEMRULIST
 *|{
 *|    DWORD   cbSize;
 *|    DWORD   nMaxItems;
 *|    DWORD   dwFlags;
 *|    HKEY    hKey;
 *|    LPCTSTR lpszSubKey;
 *|    PROC    lpfnCompare;
 *|} CREATEMRULIST, *LPCREATEMRULIST;
 *
 * MEMBERS
 *  cbSize      [I] The size of the CREATEMRULIST structure. This must be set
 *                  to sizeof(CREATEMRULIST) by the caller.
 *  nMaxItems   [I] The maximum number of items allowed in the list. Because
 *                  of the limited number of identifiers, this should be set to
 *                  a value from 1 to 30 by the caller.
 *  dwFlags     [I] If bit 0 is set, the list will be used to store binary
 *                  data, otherwise it is assumed to store strings. If bit 1
 *                  is set, every change made to the list will be reflected in
 *                  the registry immediately, otherwise changes will only be
 *                  written when the list is closed.
 *  hKey        [I] The registry key that the list should be written under.
 *                  This must be supplied by the caller.
 *  lpszSubKey  [I] A caller supplied name of a subkey under hKey to write
 *                  the list to. This may not be blank.
196
 *  lpfnCompare [I] A caller supplied comparison function, which may be either
197 198 199 200 201 202 203 204 205 206
 *                  an MRUStringCmpFn if dwFlags does not have bit 0 set, or a
 *                  MRUBinaryCmpFn otherwise.
 *
 * FUNCTIONS
 *  - Create an MRU-list with CreateMRUList() or CreateMRUListLazy().
 *  - Add items to an MRU-list with AddMRUString() or AddMRUData().
 *  - Remove items from an MRU-list with DelMRUString().
 *  - Find data in an MRU-list with FindMRUString() or FindMRUData().
 *  - Iterate through an MRU-list with EnumMRUList().
 *  - Free an MRU-list with FreeMRUList().
Alexandre Julliard's avatar
Alexandre Julliard committed
207 208
 */

209
typedef struct tagCREATEMRULISTA
Alexandre Julliard's avatar
Alexandre Julliard committed
210
{
211 212 213 214 215 216
    DWORD  cbSize;
    DWORD  nMaxItems;
    DWORD  dwFlags;
    HKEY   hKey;
    LPCSTR lpszSubKey;
    PROC   lpfnCompare;
217 218 219 220
} CREATEMRULISTA, *LPCREATEMRULISTA;

typedef struct tagCREATEMRULISTW
{
221 222 223 224 225 226
    DWORD   cbSize;
    DWORD   nMaxItems;
    DWORD   dwFlags;
    HKEY    hKey;
    LPCWSTR lpszSubKey;
    PROC    lpfnCompare;
227
} CREATEMRULISTW, *LPCREATEMRULISTW;
228

229 230 231 232 233 234 235 236 237 238 239 240 241
/* dwFlags */
#define MRUF_STRING_LIST  0 /* list will contain strings */
#define MRUF_BINARY_LIST  1 /* list will contain binary data */
#define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */

/* If list is a string list lpfnCompare has the following prototype
 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2)
 * for binary lists the prototype is
 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData)
 * where cbData is the no. of bytes to compare.
 * Need to check what return value means identical - 0?
 */

242
typedef struct tagWINEMRUITEM
243
{
244 245 246 247 248 249 250 251 252 253
    DWORD          size;        /* size of data stored               */
    DWORD          itemFlag;    /* flags                             */
    BYTE           datastart;
} WINEMRUITEM, *LPWINEMRUITEM;

/* itemFlag */
#define WMRUIF_CHANGED   0x0001 /* this dataitem changed             */

typedef struct tagWINEMRULIST
{
254 255
    CREATEMRULISTW extview;     /* original create information       */
    BOOL           isUnicode;   /* is compare fn Unicode */
256 257
    DWORD          wineFlags;   /* internal flags                    */
    DWORD          cursize;     /* current size of realMRU           */
258
    LPWSTR         realMRU;     /* pointer to string of index names  */
259 260 261 262 263 264
    LPWINEMRUITEM  *array;      /* array of pointers to data         */
                                /* in 'a' to 'z' order               */
} WINEMRULIST, *LPWINEMRULIST;

/* wineFlags */
#define WMRUF_CHANGED  0x0001   /* MRU list has changed              */
265

266
/**************************************************************************
Robert Shearman's avatar
Robert Shearman committed
267
 *              MRU_SaveChanged (internal)
268
 *
269
 * Local MRU saving code
270
 */
271
static void MRU_SaveChanged ( LPWINEMRULIST mp )
272
{
273
    UINT i, err;
274
    HKEY newkey;
275
    WCHAR realname[2];
276 277 278 279 280 281
    LPWINEMRUITEM witem;

    /* or should we do the following instead of RegOpenKeyEx:
     */

    /* open the sub key */
282
    if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
283
			      0, KEY_WRITE, &newkey))) {
284
	/* not present - what to do ??? */
285
	ERR("Could not open key, error=%d, attempting to create\n",
286
	    err);
287
	if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
288
				    0,
289
				    NULL,
290 291 292 293 294 295
				    REG_OPTION_NON_VOLATILE,
				    KEY_READ | KEY_WRITE,
				    0,
				    &newkey,
				    0))) {
	    ERR("failed to create key /%s/, err=%d\n",
296
		debugstr_w(mp->extview.lpszSubKey), err);
297 298 299 300 301
	    return;
	}
    }
    if (mp->wineFlags & WMRUF_CHANGED) {
	mp->wineFlags &= ~WMRUF_CHANGED;
302 303
	err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (LPBYTE)mp->realMRU,
			     (strlenW(mp->realMRU) + 1)*sizeof(WCHAR));
304 305 306
	if (err) {
	    ERR("error saving MRUList, err=%d\n", err);
	}
307
	TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
308 309 310 311 312 313 314
    }
    realname[1] = 0;
    for(i=0; i<mp->cursize; i++) {
	witem = mp->array[i];
	if (witem->itemFlag & WMRUIF_CHANGED) {
	    witem->itemFlag &= ~WMRUIF_CHANGED;
	    realname[0] = 'a' + i;
315 316
	    err = RegSetValueExW(newkey, realname, 0,
				 (mp->extview.dwFlags & MRUF_BINARY_LIST) ?
317 318 319
				 REG_BINARY : REG_SZ,
				 &witem->datastart, witem->size);
	    if (err) {
320
		ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
321 322
	    }
	    TRACE("saving value for name /%s/ size=%ld\n",
323
		  debugstr_w(realname), witem->size);
324 325 326 327
	}
    }
    RegCloseKey( newkey );
}
Alexandre Julliard's avatar
Alexandre Julliard committed
328

329
/**************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
330
 *              FreeMRUList [COMCTL32.152]
331
 *
Robert Shearman's avatar
Robert Shearman committed
332 333
 * Frees a most-recently-used items list.
 *
334 335 336
 * PARAMS
 *     hMRUList [I] Handle to list.
 *
Robert Shearman's avatar
Robert Shearman committed
337
 * RETURNS
338
 *     Nothing.
339
 */
340
void WINAPI FreeMRUList (HANDLE hMRUList)
341
{
342
    LPWINEMRULIST mp = (LPWINEMRULIST)hMRUList;
343
    UINT i;
344

345 346 347 348
    TRACE("(%p)\n", hMRUList);
    if (!hMRUList)
        return;

349 350 351 352 353 354 355
    if (mp->wineFlags & WMRUF_CHANGED) {
	/* need to open key and then save the info */
	MRU_SaveChanged( mp );
    }

    for(i=0; i<mp->extview.nMaxItems; i++) {
	if (mp->array[i])
356
	    Free(mp->array[i]);
357
    }
358 359 360
    Free(mp->realMRU);
    Free(mp->array);
    Free((LPWSTR)mp->extview.lpszSubKey);
361
    Free(mp);
362 363 364 365 366
}


/**************************************************************************
 *                  FindMRUData [COMCTL32.169]
367
 *
368 369 370 371 372 373 374 375 376 377 378 379 380
 * Searches binary list for item that matches lpData of length cbData.
 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
 * corresponding to item's reg. name will be stored in it ('a' -> 0).
 *
 * PARAMS
 *    hList [I] list handle
 *    lpData [I] data to find
 *    cbData [I] length of data
 *    lpRegNum [O] position in registry (maybe NULL)
 *
 * RETURNS
 *    Position in list 0 -> MRU.  -1 if item not found.
 */
381 382
INT WINAPI FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData,
                        LPINT lpRegNum)
383 384
{
    LPWINEMRULIST mp = (LPWINEMRULIST)hList;
385 386
    INT ret;
    UINT i;
387
    LPSTR dataA = NULL;
388

389 390 391
    if (!mp->extview.lpfnCompare) {
	ERR("MRU list not properly created. No compare procedure.\n");
	return -1;
392 393
    }

394 395 396
    if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) {
        DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1,
					NULL, 0, NULL, NULL);
397
	dataA = Alloc(len);
398 399 400
	WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL);
    }

401 402
    for(i=0; i<mp->cursize; i++) {
	if (mp->extview.dwFlags & MRUF_BINARY_LIST) {
403
	    if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart,
404 405 406 407
					 cbData))
		break;
	}
	else {
408 409 410 411 412 413 414
	    if(mp->isUnicode) {
	        if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart))
		    break;
	    } else {
	        DWORD len = WideCharToMultiByte(CP_ACP, 0,
						(LPWSTR)&mp->array[i]->datastart, -1,
						NULL, 0, NULL, NULL);
415
		LPSTR itemA = Alloc(len);
416 417 418 419 420
		INT cmp;
		WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
				    itemA, len, NULL, NULL);

	        cmp = mp->extview.lpfnCompare(dataA, itemA);
421
		Free(itemA);
422 423 424
		if(!cmp)
		    break;
	    }
425 426
	}
    }
427
    if(dataA)
428
        Free(dataA);
429 430 431 432 433 434
    if (i < mp->cursize)
	ret = i;
    else
	ret = -1;
    if (lpRegNum && (ret != -1))
	*lpRegNum = 'a' + i;
435

436
    TRACE("(%p, %p, %ld, %p) returning %d\n",
437
	   hList, lpData, cbData, lpRegNum, ret);
438

439
    return ret;
440 441 442
}


443 444
/**************************************************************************
 *              AddMRUData [COMCTL32.167]
445
 *
Andreas Mohr's avatar
Andreas Mohr committed
446
 * Add item to MRU binary list.  If item already exists in list then it is
447 448 449 450 451 452 453 454 455 456 457 458
 * simply moved up to the top of the list and not added again.  If list is
 * full then the least recently used item is removed to make room.
 *
 * PARAMS
 *     hList [I] Handle to list.
 *     lpData [I] ptr to data to add.
 *     cbData [I] no. of bytes of data.
 *
 * RETURNS
 *     No. corresponding to registry name where value is stored 'a' -> 0 etc.
 *     -1 on error.
 */
459
INT WINAPI AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
Alexandre Julliard's avatar
Alexandre Julliard committed
460
{
461 462
    LPWINEMRULIST mp = (LPWINEMRULIST)hList;
    LPWINEMRUITEM witem;
463
    INT i, replace;
464

465 466
    if ((replace = FindMRUData (hList, lpData, cbData, NULL)) >= 0) {
        /* Item exists, just move it to the front */
467
        LPWSTR pos = strchrW(mp->realMRU, replace + 'a');
468 469 470 471 472 473 474
        while (pos > mp->realMRU)
        {
            pos[0] = pos[-1];
            pos--;
        }
    }
    else {
475 476 477 478 479 480 481 482 483
	/* either add a new entry or replace oldest */
	if (mp->cursize < mp->extview.nMaxItems) {
	    /* Add in a new item */
	    replace = mp->cursize;
	    mp->cursize++;
	}
	else {
	    /* get the oldest entry and replace data */
	    replace = mp->realMRU[mp->cursize - 1] - 'a';
484
	    Free(mp->array[replace]);
485
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
486

487 488 489 490 491
        /* Allocate space for new item and move in the data */
        mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
        witem->itemFlag |= WMRUIF_CHANGED;
        witem->size = cbData;
        memcpy( &witem->datastart, lpData, cbData);
492

493 494 495
        /* now rotate MRU list */
        for(i=mp->cursize-1; i>=1; i--)
            mp->realMRU[i] = mp->realMRU[i-1];
496
    }
497 498 499

    /* The new item gets the front spot */
    mp->wineFlags |= WMRUF_CHANGED;
500
    mp->realMRU[0] = replace + 'a';
501

502
    TRACE("(%p, %p, %ld) adding data, /%c/ now most current\n",
503
          hList, lpData, cbData, replace+'a');
504 505 506 507 508 509

    if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) {
	/* save changed stuff right now */
	MRU_SaveChanged( mp );
    }

510
    return replace;
Alexandre Julliard's avatar
Alexandre Julliard committed
511 512
}

513
/**************************************************************************
514
 *              AddMRUStringW [COMCTL32.401]
515
 *
516
 * Add an item to an MRU string list.
517 518
 *
 * PARAMS
519 520
 *     hList      [I] Handle to list.
 *     lpszString [I] The string to add.
521 522
 *
 * RETURNS
523 524 525 526 527 528 529 530 531 532 533 534 535 536
 *   Success: The number corresponding to the registry name where the string
 *            has been stored (0 maps to 'a', 1 to 'b' and so on).
 *   Failure: -1, if hList is NULL or memory allocation fails. If lpszString
 *            is invalid, the function returns 0, and GetLastError() returns
 *            ERROR_INVALID_PARAMETER. The last error value is set only in
 *            this case.
 *
 * NOTES
 *  -If lpszString exists in the list already, it is moved to the top of the
 *   MRU list (it is not duplicated).
 *  -If the list is full the least recently used list entry is replaced with
 *   lpszString.
 *  -If this function returns 0 you should check the last error value to
 *   ensure the call really succeeded.
537
 */
538
INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
539
{
540
    TRACE("(%p,%s)\n", hList, debugstr_w(lpszString));
541

542 543 544 545 546 547 548 549 550 551 552
    if (!hList)
        return -1;

    if (!lpszString || IsBadStringPtrW(lpszString, -1))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }

    return AddMRUData(hList, lpszString,
                      (strlenW(lpszString) + 1) * sizeof(WCHAR));
553 554 555 556
}

/**************************************************************************
 *              AddMRUStringA [COMCTL32.153]
Robert Shearman's avatar
Robert Shearman committed
557 558
 *
 * See AddMRUStringW.
559
 */
560
INT WINAPI AddMRUStringA(HANDLE hList, LPCSTR lpszString)
561
{
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
    DWORD len;
    LPWSTR stringW;
    INT ret;

    TRACE("(%p,%s)\n", hList, debugstr_a(lpszString));

    if (!hList)
        return -1;

    if (IsBadStringPtrA(lpszString, -1))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
	return 0;
    }

    len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0) * sizeof(WCHAR);
    stringW = Alloc(len);
    if (!stringW)
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
581

582
    MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len/sizeof(WCHAR));
583 584 585
    ret = AddMRUData(hList, stringW, len);
    Free(stringW);
    return ret;
586
}
Alexandre Julliard's avatar
Alexandre Julliard committed
587

588 589 590 591 592 593 594 595 596 597
/**************************************************************************
 *              DelMRUString [COMCTL32.156]
 *
 * Removes item from either string or binary list (despite its name)
 *
 * PARAMS
 *    hList [I] list handle
 *    nItemPos [I] item position to remove 0 -> MRU
 *
 * RETURNS
Andreas Mohr's avatar
Andreas Mohr committed
598
 *    TRUE if successful, FALSE if nItemPos is out of range.
599
 */
600
BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
601
{
602
    FIXME("(%p, %d): stub\n", hList, nItemPos);
603
    return TRUE;
604
}
Alexandre Julliard's avatar
Alexandre Julliard committed
605

606 607
/**************************************************************************
 *                  FindMRUStringW [COMCTL32.402]
Robert Shearman's avatar
Robert Shearman committed
608 609
 *
 * See FindMRUStringA.
610
 */
611
INT WINAPI FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum)
612
{
613 614
  return FindMRUData(hList, lpszString,
                     (lstrlenW(lpszString) + 1) * sizeof(WCHAR), lpRegNum);
615 616
}

617 618
/**************************************************************************
 *                  FindMRUStringA [COMCTL32.155]
619
 *
620 621 622 623 624 625 626 627 628 629 630 631
 * Searches string list for item that matches lpszString.
 * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value
 * corresponding to item's reg. name will be stored in it ('a' -> 0).
 *
 * PARAMS
 *    hList [I] list handle
 *    lpszString [I] string to find
 *    lpRegNum [O] position in registry (maybe NULL)
 *
 * RETURNS
 *    Position in list 0 -> MRU.  -1 if item not found.
 */
632
INT WINAPI FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum)
633
{
634
    DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0);
635
    LPWSTR stringW = Alloc(len * sizeof(WCHAR));
636 637 638 639
    INT ret;

    MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len);
    ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum);
640
    Free(stringW);
641
    return ret;
642
}
Alexandre Julliard's avatar
Alexandre Julliard committed
643

644
/*************************************************************************
Robert Shearman's avatar
Robert Shearman committed
645
 *                 CreateMRUListLazy_common (internal)
646
 */
647
static HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp)
Alexandre Julliard's avatar
Alexandre Julliard committed
648
{
649
    UINT i, err;
650 651
    HKEY newkey;
    DWORD datasize, dwdisp;
652
    WCHAR realname[2];
653 654
    LPWINEMRUITEM witem;
    DWORD type;
Alexandre Julliard's avatar
Alexandre Julliard committed
655

656
    /* get space to save indices that will turn into names
657 658
     * but in order of most to least recently used
     */
659
    mp->realMRU = Alloc((mp->extview.nMaxItems + 2) * sizeof(WCHAR));
660 661 662 663

    /* get space to save pointers to actual data in order of
     * 'a' to 'z' (0 to n).
     */
664
    mp->array = Alloc(mp->extview.nMaxItems * sizeof(LPVOID));
665 666

    /* open the sub key */
667
    if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey,
668
			        0,
669
				NULL,
670
				REG_OPTION_NON_VOLATILE,
671 672 673 674 675
				KEY_READ | KEY_WRITE,
                                0,
				&newkey,
				&dwdisp))) {
	/* error - what to do ??? */
Frank Richter's avatar
Frank Richter committed
676
	ERR("(%lu %lu %lx %p %s %p): Could not open key, error=%d\n",
677
	    mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
Frank Richter's avatar
Frank Richter committed
678
	    mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
679
				 mp->extview.lpfnCompare, err);
680 681
	return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
682

683 684
    /* get values from key 'MRUList' */
    if (newkey) {
685
	datasize = (mp->extview.nMaxItems + 1) * sizeof(WCHAR);
686 687
	if((err=RegQueryValueExW( newkey, strMRUList, 0, &type,
				  (LPBYTE)mp->realMRU, &datasize))) {
688 689 690 691
	    /* not present - set size to 1 (will become 0 later) */
	    datasize = 1;
	    *mp->realMRU = 0;
	}
692 693
        else
            datasize /= sizeof(WCHAR);
694

695
	TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize);
Alexandre Julliard's avatar
Alexandre Julliard committed
696

697 698
	mp->cursize = datasize - 1;
	/* datasize now has number of items in the MRUList */
Alexandre Julliard's avatar
Alexandre Julliard committed
699

700 701 702 703
	/* get actual values for each entry */
	realname[1] = 0;
	for(i=0; i<mp->cursize; i++) {
	    realname[0] = 'a' + i;
704
	    if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) {
705
		/* not present - what to do ??? */
706
		ERR("Key %s not found 1\n", debugstr_w(realname));
707
	    }
708
	    mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
709
	    witem->size = datasize;
710
	    if(RegQueryValueExW( newkey, realname, 0, &type,
711 712
				 &witem->datastart, &datasize)) {
		/* not present - what to do ??? */
713
		ERR("Key %s not found 2\n", debugstr_w(realname));
714 715 716 717 718 719 720
	    }
	}
	RegCloseKey( newkey );
    }
    else
	mp->cursize = 0;

Frank Richter's avatar
Frank Richter committed
721
    TRACE("(%lu %lu %lx %p %s %p): Current Size = %ld\n",
722
	  mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags,
Frank Richter's avatar
Frank Richter committed
723
	  mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey),
724
	  mp->extview.lpfnCompare, mp->cursize);
725
    return (HANDLE)mp;
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727
}

728
/**************************************************************************
729
 *                  CreateMRUListLazyW [COMCTL32.404]
Robert Shearman's avatar
Robert Shearman committed
730 731
 *
 * See CreateMRUListLazyA.
732
 */
733 734
HANDLE WINAPI CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2,
                                  DWORD dwParam3, DWORD dwParam4)
735 736 737
{
    LPWINEMRULIST mp;

738
    /* Native does not check for a NULL lpcml */
739

740 741 742
    if (lpcml->cbSize != sizeof(CREATEMRULISTW) || !lpcml->hKey ||
        IsBadStringPtrW(lpcml->lpszSubKey, -1))
	return NULL;
743

744
    mp = Alloc(sizeof(WINEMRULIST));
745
    memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
746
    mp->extview.lpszSubKey = Alloc((strlenW(lpcml->lpszSubKey) + 1) * sizeof(WCHAR));
747 748 749
    strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey);
    mp->isUnicode = TRUE;

750
    return CreateMRUListLazy_common(mp);
751 752 753 754
}

/**************************************************************************
 *                  CreateMRUListLazyA [COMCTL32.157]
Robert Shearman's avatar
Robert Shearman committed
755 756 757 758 759 760 761 762 763 764 765
 *
 * Creates a most-recently-used list.
 *
 * PARAMS
 *     lpcml    [I] ptr to CREATEMRULIST structure.
 *     dwParam2 [I] Unknown
 *     dwParam3 [I] Unknown
 *     dwParam4 [I] Unknown
 *
 * RETURNS
 *     Handle to MRU list.
766
 */
767 768
HANDLE WINAPI CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2,
                                  DWORD dwParam3, DWORD dwParam4)
769 770 771 772
{
    LPWINEMRULIST mp;
    DWORD len;

773
    /* Native does not check for a NULL lpcml */
774

775 776
    if (lpcml->cbSize != sizeof(CREATEMRULISTA) || !lpcml->hKey ||
        IsBadStringPtrA(lpcml->lpszSubKey, -1))
777 778
	return 0;

779
    mp = Alloc(sizeof(WINEMRULIST));
780 781
    memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW));
    len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0);
782
    mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
783 784 785 786 787 788 789 790 791
    MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1,
			(LPWSTR)mp->extview.lpszSubKey, len);
    mp->isUnicode = FALSE;
    return CreateMRUListLazy_common(mp);
}

/**************************************************************************
 *              CreateMRUListW [COMCTL32.400]
 *
Robert Shearman's avatar
Robert Shearman committed
792
 * See CreateMRUListA.
793
 */
794
HANDLE WINAPI CreateMRUListW (LPCREATEMRULISTW lpcml)
795 796 797 798 799 800
{
    return CreateMRUListLazyW(lpcml, 0, 0, 0);
}

/**************************************************************************
 *              CreateMRUListA [COMCTL32.151]
Robert Shearman's avatar
Robert Shearman committed
801 802 803 804 805 806 807 808
 *
 * Creates a most-recently-used list.
 *
 * PARAMS
 *     lpcml [I] ptr to CREATEMRULIST structure.
 *
 * RETURNS
 *     Handle to MRU list.
809
 */
810
HANDLE WINAPI CreateMRUListA (LPCREATEMRULISTA lpcml)
811 812 813 814 815 816 817 818
{
     return CreateMRUListLazyA (lpcml, 0, 0, 0);
}


/**************************************************************************
 *                EnumMRUListW [COMCTL32.403]
 *
Robert Shearman's avatar
Robert Shearman committed
819
 * Enumerate item in a most-recenty-used list
820 821 822 823 824 825 826 827 828 829 830 831
 *
 * PARAMS
 *    hList [I] list handle
 *    nItemPos [I] item position to enumerate
 *    lpBuffer [O] buffer to receive item
 *    nBufferSize [I] size of buffer
 *
 * RETURNS
 *    For binary lists specifies how many bytes were copied to buffer, for
 *    string lists specifies full length of string.  Enumerating past the end
 *    of list returns -1.
 *    If lpBuffer == NULL or nItemPos is -ve return value is no. of items in
832
 *    the list.
833
 */
834 835
INT WINAPI EnumMRUListW (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
                         DWORD nBufferSize)
836
{
837 838 839 840 841 842 843 844 845 846
    LPWINEMRULIST mp = (LPWINEMRULIST) hList;
    LPWINEMRUITEM witem;
    INT desired, datasize;

    if (nItemPos >= mp->cursize) return -1;
    if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
    desired = mp->realMRU[nItemPos];
    desired -= 'a';
    TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
    witem = mp->array[desired];
847
    datasize = min( witem->size, nBufferSize );
848
    memcpy( lpBuffer, &witem->datastart, datasize);
849
    TRACE("(%p, %d, %p, %ld): returning len=%d\n",
850 851
	  hList, nItemPos, lpBuffer, nBufferSize, datasize);
    return datasize;
852
}
Alexandre Julliard's avatar
Alexandre Julliard committed
853

854 855
/**************************************************************************
 *                EnumMRUListA [COMCTL32.154]
856
 *
Robert Shearman's avatar
Robert Shearman committed
857
 * See EnumMRUListW.
858
 */
859 860
INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
                         DWORD nBufferSize)
861 862 863 864 865 866 867 868 869 870 871 872 873
{
    LPWINEMRULIST mp = (LPWINEMRULIST) hList;
    LPWINEMRUITEM witem;
    INT desired, datasize;
    DWORD lenA;

    if (nItemPos >= mp->cursize) return -1;
    if ((nItemPos < 0) || !lpBuffer) return mp->cursize;
    desired = mp->realMRU[nItemPos];
    desired -= 'a';
    TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
    witem = mp->array[desired];
    if(mp->extview.dwFlags & MRUF_BINARY_LIST) {
874
        datasize = min( witem->size, nBufferSize );
875 876 877 878 879 880 881 882
	memcpy( lpBuffer, &witem->datastart, datasize);
    } else {
        lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
				   NULL, 0, NULL, NULL);
	datasize = min( witem->size, nBufferSize );
	WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
			    lpBuffer, datasize, NULL, NULL);
    }
883
    TRACE("(%p, %d, %p, %ld): returning len=%d\n",
884 885 886
	  hList, nItemPos, lpBuffer, nBufferSize, datasize);
    return datasize;
}
887

888

Alexandre Julliard's avatar
Alexandre Julliard committed
889 890 891
/**************************************************************************
 * Str_GetPtrA [COMCTL32.233]
 *
Robert Shearman's avatar
Robert Shearman committed
892 893
 * Copies a string into a destination buffer.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
894
 * PARAMS
Robert Shearman's avatar
Robert Shearman committed
895 896 897
 *     lpSrc   [I] Source string
 *     lpDest  [O] Destination buffer
 *     nMaxLen [I] Size of buffer in characters
Alexandre Julliard's avatar
Alexandre Julliard committed
898 899
 *
 * RETURNS
Robert Shearman's avatar
Robert Shearman committed
900
 *     The number of characters copied.
Alexandre Julliard's avatar
Alexandre Julliard committed
901
 */
902
INT WINAPI Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen)
Alexandre Julliard's avatar
Alexandre Julliard committed
903
{
904
    INT len;
Alexandre Julliard's avatar
Alexandre Julliard committed
905

906
    TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
Alexandre Julliard's avatar
Alexandre Julliard committed
907 908

    if (!lpDest && lpSrc)
909
	return strlen (lpSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
910 911 912 913 914 915 916 917 918

    if (nMaxLen == 0)
	return 0;

    if (lpSrc == NULL) {
	lpDest[0] = '\0';
	return 0;
    }

919
    len = strlen (lpSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
920 921 922 923 924 925 926 927
    if (len >= nMaxLen)
	len = nMaxLen - 1;

    RtlMoveMemory (lpDest, lpSrc, len);
    lpDest[len] = '\0';

    return len;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
928 929 930 931 932


/**************************************************************************
 * Str_SetPtrA [COMCTL32.234]
 *
Robert Shearman's avatar
Robert Shearman committed
933 934
 * Makes a copy of a string, allocating memory if necessary.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
935
 * PARAMS
Robert Shearman's avatar
Robert Shearman committed
936 937
 *     lppDest [O] Pointer to destination string
 *     lpSrc   [I] Source string
Alexandre Julliard's avatar
Alexandre Julliard committed
938 939
 *
 * RETURNS
Robert Shearman's avatar
Robert Shearman committed
940 941 942 943 944 945
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Set lpSrc to NULL to free the memory allocated by a previous call
 *     to this function.
Alexandre Julliard's avatar
Alexandre Julliard committed
946
 */
947
BOOL WINAPI Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc)
Alexandre Julliard's avatar
Alexandre Julliard committed
948
{
949
    TRACE("(%p %p)\n", lppDest, lpSrc);
950

Alexandre Julliard's avatar
Alexandre Julliard committed
951
    if (lpSrc) {
952
	LPSTR ptr = ReAlloc (*lppDest, strlen (lpSrc) + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
953 954
	if (!ptr)
	    return FALSE;
955
	strcpy (ptr, lpSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
956 957 958 959
	*lppDest = ptr;
    }
    else {
	if (*lppDest) {
960
	    Free (*lppDest);
Alexandre Julliard's avatar
Alexandre Julliard committed
961 962 963 964 965 966 967 968 969 970 971
	    *lppDest = NULL;
	}
    }

    return TRUE;
}


/**************************************************************************
 * Str_GetPtrW [COMCTL32.235]
 *
Robert Shearman's avatar
Robert Shearman committed
972
 * See Str_GetPtrA.
Alexandre Julliard's avatar
Alexandre Julliard committed
973
 */
974
INT WINAPI Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
Alexandre Julliard's avatar
Alexandre Julliard committed
975
{
976
    INT len;
Alexandre Julliard's avatar
Alexandre Julliard committed
977

978
    TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
Alexandre Julliard's avatar
Alexandre Julliard committed
979 980

    if (!lpDest && lpSrc)
981
	return strlenW (lpSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
982 983 984 985 986 987 988 989 990

    if (nMaxLen == 0)
	return 0;

    if (lpSrc == NULL) {
	lpDest[0] = L'\0';
	return 0;
    }

991
    len = strlenW (lpSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
    if (len >= nMaxLen)
	len = nMaxLen - 1;

    RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR));
    lpDest[len] = L'\0';

    return len;
}


/**************************************************************************
 * Str_SetPtrW [COMCTL32.236]
 *
Robert Shearman's avatar
Robert Shearman committed
1005
 * See Str_SetPtrA.
Alexandre Julliard's avatar
Alexandre Julliard committed
1006
 */
1007
BOOL WINAPI Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1008
{
1009
    TRACE("(%p %p)\n", lppDest, lpSrc);
1010

Alexandre Julliard's avatar
Alexandre Julliard committed
1011
    if (lpSrc) {
1012
	INT len = strlenW (lpSrc) + 1;
1013
	LPWSTR ptr = ReAlloc (*lppDest, len * sizeof(WCHAR));
Alexandre Julliard's avatar
Alexandre Julliard committed
1014
	if (!ptr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1015
	    return FALSE;
1016
	strcpyW (ptr, lpSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1017
	*lppDest = ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1018
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1019 1020
    else {
	if (*lppDest) {
1021
	    Free (*lppDest);
Alexandre Julliard's avatar
Alexandre Julliard committed
1022 1023
	    *lppDest = NULL;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1024 1025
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1026
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1027 1028 1029
}


1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
/**************************************************************************
 * Str_GetPtrWtoA [internal]
 *
 * Converts a unicode string into a multi byte string
 *
 * PARAMS
 *     lpSrc   [I] Pointer to the unicode source string
 *     lpDest  [O] Pointer to caller supplied storage for the multi byte string
 *     nMaxLen [I] Size, in bytes, of the destination buffer
 *
 * RETURNS
 *     Length, in bytes, of the converted string.
 */

1044
INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen)
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
{
    INT len;

    TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen);

    if (!lpDest && lpSrc)
	return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);

    if (nMaxLen == 0)
	return 0;

    if (lpSrc == NULL) {
	lpDest[0] = '\0';
	return 0;
    }

    len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL);
    if (len >= nMaxLen)
	len = nMaxLen - 1;

    WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL);
    lpDest[len] = '\0';

    return len;
}


/**************************************************************************
 * Str_SetPtrAtoW [internal]
 *
 * Converts a multi byte string to a unicode string.
 * If the pointer to the destination buffer is NULL a buffer is allocated.
 * If the destination buffer is too small to keep the converted multi byte
 * string the destination buffer is reallocated. If the source pointer is
 * NULL, the destination buffer is freed.
 *
 * PARAMS
 *     lppDest [I/O] pointer to a pointer to the destination buffer
 *     lpSrc   [I] pointer to a multi byte string
 *
 * RETURNS
 *     TRUE: conversion successful
 *     FALSE: error
 */
1089
BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc)
1090 1091 1092 1093 1094
{
    TRACE("(%p %s)\n", lppDest, lpSrc);

    if (lpSrc) {
	INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0);
1095
	LPWSTR ptr = ReAlloc (*lppDest, len*sizeof(WCHAR));
1096 1097 1098 1099 1100 1101 1102 1103

	if (!ptr)
	    return FALSE;
	MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len);
	*lppDest = ptr;
    }
    else {
	if (*lppDest) {
1104
	    Free (*lppDest);
1105 1106 1107 1108 1109 1110 1111 1112
	    *lppDest = NULL;
	}
    }

    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1113
/**************************************************************************
1114
 * Notification functions
Alexandre Julliard's avatar
Alexandre Julliard committed
1115 1116
 */

1117
typedef struct tagNOTIFYDATA
Alexandre Julliard's avatar
Alexandre Julliard committed
1118
{
1119 1120 1121 1122 1123 1124 1125
    HWND hwndFrom;
    HWND hwndTo;
    DWORD  dwParam3;
    DWORD  dwParam4;
    DWORD  dwParam5;
    DWORD  dwParam6;
} NOTIFYDATA, *LPNOTIFYDATA;
Alexandre Julliard's avatar
Alexandre Julliard committed
1126 1127 1128


/**************************************************************************
1129
 * DoNotify [Internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
1130 1131
 */

1132
static LRESULT DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1133
{
1134 1135 1136
    NMHDR nmhdr;
    LPNMHDR lpNmh = NULL;
    UINT idFrom = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1137

1138 1139 1140
    TRACE("(%p %p %d %p 0x%08lx)\n",
	   lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
	   lpNotify->dwParam5);
Alexandre Julliard's avatar
Alexandre Julliard committed
1141

1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    if (!lpNotify->hwndTo)
	return 0;

    if (lpNotify->hwndFrom == (HWND)-1) {
	lpNmh = lpHdr;
	idFrom = lpHdr->idFrom;
    }
    else {
	if (lpNotify->hwndFrom)
	    idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
Alexandre Julliard's avatar
Alexandre Julliard committed
1152

1153
	lpNmh = (lpHdr) ? lpHdr : &nmhdr;
1154

1155 1156 1157 1158
	lpNmh->hwndFrom = lpNotify->hwndFrom;
	lpNmh->idFrom = idFrom;
	lpNmh->code = uCode;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1159

1160
    return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
Alexandre Julliard's avatar
Alexandre Julliard committed
1161 1162 1163 1164
}


/**************************************************************************
1165
 * SendNotify [COMCTL32.341]
Alexandre Julliard's avatar
Alexandre Julliard committed
1166
 *
1167
 * Sends a WM_NOTIFY message to the specified window.
Alexandre Julliard's avatar
Alexandre Julliard committed
1168 1169
 *
 * PARAMS
1170 1171 1172 1173
 *     hwndTo   [I] Window to receive the message
 *     hwndFrom [I] Window that the message is from (see notes)
 *     uCode    [I] Notification code
 *     lpHdr    [I] The NMHDR and any additional information to send or NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1174 1175
 *
 * RETURNS
1176 1177 1178 1179 1180 1181 1182
 *     Success: return value from notification
 *     Failure: 0
 *
 * NOTES
 *     If hwndFrom is -1 then the identifier of the control sending the
 *     message is taken from the NMHDR structure.
 *     If hwndFrom is not -1 then lpHdr can be NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1183
 */
1184
LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1185
{
1186
    NOTIFYDATA notify;
1187

1188 1189
    TRACE("(%p %p %d %p)\n",
	   hwndTo, hwndFrom, uCode, lpHdr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1190

1191 1192 1193 1194
    notify.hwndFrom = hwndFrom;
    notify.hwndTo   = hwndTo;
    notify.dwParam5 = 0;
    notify.dwParam6 = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1195

1196
    return DoNotify (&notify, uCode, lpHdr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1197 1198 1199 1200
}


/**************************************************************************
1201
 * SendNotifyEx [COMCTL32.342]
Alexandre Julliard's avatar
Alexandre Julliard committed
1202
 *
1203
 * Sends a WM_NOTIFY message to the specified window.
Robert Shearman's avatar
Robert Shearman committed
1204
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1205
 * PARAMS
1206 1207 1208 1209 1210
 *     hwndFrom [I] Window to receive the message
 *     hwndTo   [I] Window that the message is from
 *     uCode    [I] Notification code
 *     lpHdr    [I] The NMHDR and any additional information to send or NULL
 *     dwParam5 [I] Unknown
Alexandre Julliard's avatar
Alexandre Julliard committed
1211 1212
 *
 * RETURNS
1213 1214 1215 1216 1217 1218 1219
 *     Success: return value from notification
 *     Failure: 0
 *
 * NOTES
 *     If hwndFrom is -1 then the identifier of the control sending the
 *     message is taken from the NMHDR structure.
 *     If hwndFrom is not -1 then lpHdr can be NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1220
 */
1221 1222
LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
                             LPNMHDR lpHdr, DWORD dwParam5)
Alexandre Julliard's avatar
Alexandre Julliard committed
1223
{
1224 1225
    NOTIFYDATA notify;
    HWND hwndNotify;
Alexandre Julliard's avatar
Alexandre Julliard committed
1226

1227 1228
    TRACE("(%p %p %d %p 0x%08lx)\n",
	   hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
Alexandre Julliard's avatar
Alexandre Julliard committed
1229

1230 1231 1232 1233 1234 1235 1236
    hwndNotify = hwndTo;
    if (!hwndTo) {
	if (IsWindow (hwndFrom)) {
	    hwndNotify = GetParent (hwndFrom);
	    if (!hwndNotify)
		return 0;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1237 1238
    }

1239 1240 1241 1242
    notify.hwndFrom = hwndFrom;
    notify.hwndTo   = hwndNotify;
    notify.dwParam5 = dwParam5;
    notify.dwParam6 = 0;
1243 1244

    return DoNotify (&notify, uCode, lpHdr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1245
}