commctrl.c 49.7 KB
Newer Older
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2 3 4
 * Common controls functions
 *
 * Copyright 1997 Dimitrie O. Paun
5
 * Copyright 1998,2000 Eric Kohl
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22 23 24 25
 *
 * NOTES
 * 
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair.
 *
Robert Shearman's avatar
Robert Shearman committed
26
 * Unless otherwise noted, we believe this code to be complete, as per
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
 *
 * TODO
 *   -- implement GetMUILanguage + InitMUILanguage
 *   -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW
 *   -- FIXMEs + BUGS (search for them)
 *
 * Control Classes
 *   -- ICC_ANIMATE_CLASS
 *   -- ICC_BAR_CLASSES
 *   -- ICC_COOL_CLASSES
 *   -- ICC_DATE_CLASSES
 *   -- ICC_HOTKEY_CLASS
 *   -- ICC_INTERNET_CLASSES
42
 *   -- ICC_LINK_CLASS
43 44 45 46 47 48 49 50 51 52
 *   -- ICC_LISTVIEW_CLASSES
 *   -- ICC_NATIVEFNTCTL_CLASS
 *   -- ICC_PAGESCROLLER_CLASS
 *   -- ICC_PROGRESS_CLASS
 *   -- ICC_STANDARD_CLASSES (not yet implemented)
 *   -- ICC_TAB_CLASSES
 *   -- ICC_TREEVIEW_CLASSES
 *   -- ICC_UPDOWN_CLASS
 *   -- ICC_USEREX_CLASSES
 *   -- ICC_WIN95_CLASSES
Alexandre Julliard's avatar
Alexandre Julliard committed
53 54
 */

55
#include <stdarg.h>
56
#include <string.h>
57
#include <stdlib.h>
58

59
#include "windef.h"
60
#include "winbase.h"
61 62 63
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
64
#include "commctrl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
65
#include "winerror.h"
66
#include "winreg.h"
67
#define NO_SHLWAPI_STREAM
68
#include "shlwapi.h"
Gerard Patel's avatar
Gerard Patel committed
69
#include "comctl32.h"
70
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
71

72
WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
73

74 75 76

#define NAME       "microsoft.windows.common-controls"
#define FILE       "comctl32.dll"
77
#define VERSION    "6.0.2600.2982"
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
#define PUBLIC_KEY "6595b64144ccf1df"

#ifdef __i386__
#define ARCH "x86"
#elif defined __x86_64__
#define ARCH "amd64"
#else
#define ARCH "none"
#endif

static const char manifest[] =
    "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
    "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
    "  <assemblyIdentity type=\"win32\" name=\"" NAME "\" version=\"" VERSION "\" processorArchitecture=\"" ARCH "\" publicKeyToken=\"" PUBLIC_KEY "\"/>\n"
    "  <file name=\"" FILE "\">\n"
    "    <windowClass>Button</windowClass>\n"
    "    <windowClass>ButtonListBox</windowClass>\n"
    "    <windowClass>ComboBoxEx32</windowClass>\n"
    "    <windowClass>ComboLBox</windowClass>\n"
    "    <windowClass>Combobox</windowClass>\n"
    "    <windowClass>Edit</windowClass>\n"
    "    <windowClass>Listbox</windowClass>\n"
    "    <windowClass>NativeFontCtl</windowClass>\n"
    "    <windowClass>ReBarWindow32</windowClass>\n"
    "    <windowClass>ScrollBar</windowClass>\n"
    "    <windowClass>Static</windowClass>\n"
    "    <windowClass>SysAnimate32</windowClass>\n"
    "    <windowClass>SysDateTimePick32</windowClass>\n"
    "    <windowClass>SysHeader32</windowClass>\n"
    "    <windowClass>SysIPAddress32</windowClass>\n"
    "    <windowClass>SysLink</windowClass>\n"
    "    <windowClass>SysListView32</windowClass>\n"
    "    <windowClass>SysMonthCal32</windowClass>\n"
    "    <windowClass>SysPager</windowClass>\n"
    "    <windowClass>SysTabControl32</windowClass>\n"
    "    <windowClass>SysTreeView32</windowClass>\n"
    "    <windowClass>ToolbarWindow32</windowClass>\n"
    "    <windowClass>msctls_hotkey32</windowClass>\n"
    "    <windowClass>msctls_progress32</windowClass>\n"
    "    <windowClass>msctls_statusbar32</windowClass>\n"
    "    <windowClass>msctls_trackbar32</windowClass>\n"
    "    <windowClass>msctls_updown32</windowClass>\n"
    "    <windowClass>tooltips_class32</windowClass>\n"
    "  </file>\n"
    "</assembly>\n";

static const char manifest_filename[] = ARCH "_" NAME "_" PUBLIC_KEY "_" VERSION "_none_deadbeef.manifest";

126
static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
127

128
static LPWSTR COMCTL32_wSubclass = NULL;
129
HMODULE COMCTL32_hModule = 0;
130
static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
131
HBRUSH  COMCTL32_hPattern55AABrush = NULL;
132
COMCTL32_SysColor  comctl32_color;
133

134
static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
135 136 137 138 139 140

static const WORD wPattern55AA[] =
{
    0x5555, 0xaaaa, 0x5555, 0xaaaa,
    0x5555, 0xaaaa, 0x5555, 0xaaaa
};
141

142 143 144
static const WCHAR strCC32SubclassInfo[] = {
    'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
};
145

146 147
static BOOL create_manifest( BOOL install )
{
148 149
    static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s',0};
    static const WCHAR manifestsW[] = {'\\','m','a','n','i','f','e','s','t','s','\\',0};
150 151 152 153 154 155 156 157

    DWORD len, written;
    WCHAR *buffer;
    HANDLE file;
    BOOL ret = FALSE;

    len = MultiByteToWideChar( CP_UTF8, 0, manifest_filename, sizeof(manifest_filename), NULL, 0 );
    len += GetWindowsDirectoryW( NULL, 0 );
158 159 160
    len += lstrlenW(winsxsW);
    len += lstrlenW(manifestsW);
    if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
161
    GetWindowsDirectoryW( buffer, len );
162 163 164 165
    lstrcatW( buffer, winsxsW );
    CreateDirectoryW( buffer, NULL );
    lstrcatW( buffer, manifestsW );
    CreateDirectoryW( buffer, NULL );
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
    MultiByteToWideChar( CP_UTF8, 0, manifest_filename, sizeof(manifest_filename),
                         buffer + lstrlenW(buffer), len );
    if (install)
    {
        file = CreateFileW( buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
        if (file != INVALID_HANDLE_VALUE)
        {
            ret = (WriteFile( file, manifest, sizeof(manifest)-1, &written, NULL ) &&
                   written == sizeof(manifest)-1);
            CloseHandle( file );
            if (!ret) DeleteFileW( buffer );
            else TRACE("created %s\n", debugstr_w(buffer));
        }
    }
    else ret = DeleteFileW( buffer );

    HeapFree( GetProcessHeap(), 0, buffer );
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
187
/***********************************************************************
188 189 190
 * DllMain [Internal]
 *
 * Initializes the internal 'COMCTL32.DLL'.
Alexandre Julliard's avatar
Alexandre Julliard committed
191 192
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
193
 *     hinstDLL    [I] handle to the 'dlls' instance
Alexandre Julliard's avatar
Alexandre Julliard committed
194
 *     fdwReason   [I]
195
 *     lpvReserved [I] reserverd, must be NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
196
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
197 198 199
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
200
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
201

202
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Alexandre Julliard's avatar
Alexandre Julliard committed
203
{
204
    TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
Alexandre Julliard's avatar
Alexandre Julliard committed
205 206 207

    switch (fdwReason) {
	case DLL_PROCESS_ATTACH:
208 209
            DisableThreadLibraryCalls(hinstDLL);

210
            COMCTL32_hModule = hinstDLL;
211 212

            /* add global subclassing atom (used by 'tooltip' and 'updown') */
Frank Richter's avatar
Frank Richter committed
213
            COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
214
            TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
215 216 217 218 219

            /* create local pattern brush */
            COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
            COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);

220 221 222
	    /* Get all the colors at DLL load */
	    COMCTL32_RefreshSysColors();

223
            /* like comctl32 5.82+ register all the common control classes */
224
            ANIMATE_Register ();
225 226
            COMBOEX_Register ();
            DATETIME_Register ();
227 228 229
            FLATSB_Register ();
            HEADER_Register ();
            HOTKEY_Register ();
230
            IPADDRESS_Register ();
231
            LISTVIEW_Register ();
232 233 234
            MONTHCAL_Register ();
            NATIVEFONT_Register ();
            PAGER_Register ();
235
            PROGRESS_Register ();
236
            REBAR_Register ();
237
            STATUS_Register ();
238
            SYSLINK_Register ();
239 240 241 242 243 244
            TAB_Register ();
            TOOLBAR_Register ();
            TOOLTIPS_Register ();
            TRACKBAR_Register ();
            TREEVIEW_Register ();
            UPDOWN_Register ();
245 246 247

            /* subclass user32 controls */
            THEMING_Initialize ();
248
            break;
249 250

	case DLL_PROCESS_DETACH:
251 252 253
            /* clean up subclassing */ 
            THEMING_Uninitialize();

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
            /* unregister all common control classes */
            ANIMATE_Unregister ();
            COMBOEX_Unregister ();
            DATETIME_Unregister ();
            FLATSB_Unregister ();
            HEADER_Unregister ();
            HOTKEY_Unregister ();
            IPADDRESS_Unregister ();
            LISTVIEW_Unregister ();
            MONTHCAL_Unregister ();
            NATIVEFONT_Unregister ();
            PAGER_Unregister ();
            PROGRESS_Unregister ();
            REBAR_Unregister ();
            STATUS_Unregister ();
269
            SYSLINK_Unregister ();
270 271 272 273 274 275 276 277 278
            TAB_Unregister ();
            TOOLBAR_Unregister ();
            TOOLTIPS_Unregister ();
            TRACKBAR_Unregister ();
            TREEVIEW_Unregister ();
            UPDOWN_Unregister ();

            /* delete local pattern brush */
            DeleteObject (COMCTL32_hPattern55AABrush);
279
            COMCTL32_hPattern55AABrush = NULL;
280
            DeleteObject (COMCTL32_hPattern55AABitmap);
281
            COMCTL32_hPattern55AABitmap = NULL;
282 283

            /* delete global subclassing atom */
284 285 286
            GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
            TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
            COMCTL32_wSubclass = NULL;
287
            break;
Alexandre Julliard's avatar
Alexandre Julliard committed
288
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
289

Alexandre Julliard's avatar
Alexandre Julliard committed
290
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
291
}
Alexandre Julliard's avatar
Alexandre Julliard committed
292 293


Alexandre Julliard's avatar
Alexandre Julliard committed
294 295 296
/***********************************************************************
 * MenuHelp [COMCTL32.2]
 *
297 298 299
 * Handles the setting of status bar help messages when the user
 * selects menu items.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
300
 * PARAMS
301 302 303 304 305
 *     uMsg       [I] message (WM_MENUSELECT) (see NOTES)
 *     wParam     [I] wParam of the message uMsg
 *     lParam     [I] lParam of the message uMsg
 *     hMainMenu  [I] handle to the application's main menu
 *     hInst      [I] handle to the module that contains string resources
Alexandre Julliard's avatar
Alexandre Julliard committed
306
 *     hwndStatus [I] handle to the status bar window
307
 *     lpwIDs     [I] pointer to an array of integers (see NOTES)
Alexandre Julliard's avatar
Alexandre Julliard committed
308 309
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
310
 *     No return value
Alexandre Julliard's avatar
Alexandre Julliard committed
311 312
 *
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
313
 *     The official documentation is incomplete!
314 315 316
 *     This is the correct documentation:
 *
 *     uMsg:
Andreas Mohr's avatar
Andreas Mohr committed
317
 *     MenuHelp() does NOT handle WM_COMMAND messages! It only handles
318 319 320 321
 *     WM_MENUSELECT messages.
 *
 *     lpwIDs:
 *     (will be written ...)
Alexandre Julliard's avatar
Alexandre Julliard committed
322 323 324
 */

VOID WINAPI
325
MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
326
	  HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
Alexandre Julliard's avatar
Alexandre Julliard committed
327
{
328
    UINT uMenuID = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
329

330
    if (!IsWindow (hwndStatus))
Alexandre Julliard's avatar
Alexandre Julliard committed
331
	return;
Alexandre Julliard's avatar
Alexandre Julliard committed
332 333 334

    switch (uMsg) {
	case WM_MENUSELECT:
335
	    TRACE("WM_MENUSELECT wParam=0x%lX lParam=0x%lX\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
336
		   wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
337 338 339

            if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
                /* menu was closed */
340
		TRACE("menu was closed!\n");
341
                SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
342
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
343 344 345
	    else {
		/* menu item was selected */
		if (HIWORD(wParam) & MF_POPUP)
346
		    uMenuID = *(lpwIDs+1);
Alexandre Julliard's avatar
Alexandre Julliard committed
347
		else
348
		    uMenuID = (UINT)LOWORD(wParam);
349
		TRACE("uMenuID = %u\n", uMenuID);
Alexandre Julliard's avatar
Alexandre Julliard committed
350 351

		if (uMenuID) {
352
		    WCHAR szText[256];
Alexandre Julliard's avatar
Alexandre Julliard committed
353

354
		    if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
355
			szText[0] = '\0';
Alexandre Julliard's avatar
Alexandre Julliard committed
356

357
		    SendMessageW (hwndStatus, SB_SETTEXTW,
Alexandre Julliard's avatar
Alexandre Julliard committed
358
				    255 | SBT_NOBORDERS, (LPARAM)szText);
359
		    SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
360 361 362
		}
	    }
	    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
363

364
        case WM_COMMAND :
365
	    TRACE("WM_COMMAND wParam=0x%lX lParam=0x%lX\n",
366 367 368 369 370 371 372 373
		   wParam, lParam);
	    /* WM_COMMAND is not invalid since it is documented
	     * in the windows api reference. So don't output
             * any FIXME for WM_COMMAND
             */
	    WARN("We don't care about the WM_COMMAND\n");
	    break;

Alexandre Julliard's avatar
Alexandre Julliard committed
374
	default:
375
	    FIXME("Invalid Message 0x%x!\n", uMsg);
Alexandre Julliard's avatar
Alexandre Julliard committed
376
	    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
377 378 379 380 381
    }
}


/***********************************************************************
382
 * ShowHideMenuCtl [COMCTL32.3]
Alexandre Julliard's avatar
Alexandre Julliard committed
383 384 385 386 387 388 389 390 391 392 393 394 395
 *
 * Shows or hides controls and updates the corresponding menu item.
 *
 * PARAMS
 *     hwnd   [I] handle to the client window.
 *     uFlags [I] menu command id.
 *     lpInfo [I] pointer to an array of integers. (See NOTES.)
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
396 397 398 399 400 401 402
 *     The official documentation is incomplete!
 *     This is the correct documentation:
 *
 *     hwnd
 *     Handle to the window that contains the menu and controls.
 *
 *     uFlags
403
 *     Identifier of the menu item to receive or lose a check mark.
Alexandre Julliard's avatar
Alexandre Julliard committed
404 405 406
 *
 *     lpInfo
 *     The array of integers contains pairs of values. BOTH values of
407
 *     the first pair must be the handles to the application's main menu.
Alexandre Julliard's avatar
Alexandre Julliard committed
408 409 410
 *     Each subsequent pair consists of a menu id and control id.
 */

411
BOOL WINAPI
Frank Richter's avatar
Frank Richter committed
412
ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
413
{
414
    LPINT lpMenuId;
Alexandre Julliard's avatar
Alexandre Julliard committed
415

416
    TRACE("%p, %lx, %p\n", hwnd, uFlags, lpInfo);
Alexandre Julliard's avatar
Alexandre Julliard committed
417 418 419 420 421 422 423 424 425 426 427 428

    if (lpInfo == NULL)
	return FALSE;

    if (!(lpInfo[0]) || !(lpInfo[1]))
	return FALSE;

    /* search for control */
    lpMenuId = &lpInfo[2];
    while (*lpMenuId != uFlags)
	lpMenuId += 2;

Frank Richter's avatar
Frank Richter committed
429
    if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
Alexandre Julliard's avatar
Alexandre Julliard committed
430
	/* uncheck menu item */
Frank Richter's avatar
Frank Richter committed
431
	CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
Alexandre Julliard's avatar
Alexandre Julliard committed
432 433 434

	/* hide control */
	lpMenuId++;
435
	SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
436 437 438 439
			SWP_HIDEWINDOW);
    }
    else {
	/* check menu item */
Frank Richter's avatar
Frank Richter committed
440
	CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
Alexandre Julliard's avatar
Alexandre Julliard committed
441 442 443

	/* show control */
	lpMenuId++;
444
	SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
445 446 447 448 449 450 451 452 453 454
			SWP_SHOWWINDOW);
    }

    return TRUE;
}


/***********************************************************************
 * GetEffectiveClientRect [COMCTL32.4]
 *
455 456
 * Calculates the coordinates of a rectangle in the client area.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
457 458 459
 * PARAMS
 *     hwnd   [I] handle to the client window.
 *     lpRect [O] pointer to the rectangle of the client window
460
 *     lpInfo [I] pointer to an array of integers (see NOTES)
Alexandre Julliard's avatar
Alexandre Julliard committed
461 462
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
463
 *     No return value.
Alexandre Julliard's avatar
Alexandre Julliard committed
464 465
 *
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
466
 *     The official documentation is incomplete!
467 468 469
 *     This is the correct documentation:
 *
 *     lpInfo
470
 *     (will be written ...)
Alexandre Julliard's avatar
Alexandre Julliard committed
471 472 473
 */

VOID WINAPI
474
GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
475
{
476
    RECT rcCtrl;
477
    const INT *lpRun;
478
    HWND hwndCtrl;
Alexandre Julliard's avatar
Alexandre Julliard committed
479

Frank Richter's avatar
Frank Richter committed
480 481
    TRACE("(%p %p %p)\n",
	   hwnd, lpRect, lpInfo);
Alexandre Julliard's avatar
Alexandre Julliard committed
482

483
    GetClientRect (hwnd, lpRect);
Alexandre Julliard's avatar
Alexandre Julliard committed
484 485 486 487 488 489 490
    lpRun = lpInfo;

    do {
	lpRun += 2;
	if (*lpRun == 0)
	    return;
	lpRun++;
491
	hwndCtrl = GetDlgItem (hwnd, *lpRun);
492
	if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
493
	    TRACE("control id 0x%x\n", *lpRun);
494
	    GetWindowRect (hwndCtrl, &rcCtrl);
495
	    MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
496
	    SubtractRect (lpRect, lpRect, &rcCtrl);
Alexandre Julliard's avatar
Alexandre Julliard committed
497 498 499 500 501 502
	}
	lpRun++;
    } while (*lpRun);
}


Alexandre Julliard's avatar
Alexandre Julliard committed
503
/***********************************************************************
504
 * DrawStatusTextW [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
505 506 507 508 509 510 511
 *
 * Draws text with borders, like in a status bar.
 *
 * PARAMS
 *     hdc   [I] handle to the window's display context
 *     lprc  [I] pointer to a rectangle
 *     text  [I] pointer to the text
512
 *     style [I] drawing style
Alexandre Julliard's avatar
Alexandre Julliard committed
513 514 515
 *
 * RETURNS
 *     No return value.
516 517 518 519
 *
 * NOTES
 *     The style variable can have one of the following values:
 *     (will be written ...)
Alexandre Julliard's avatar
Alexandre Julliard committed
520
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
521

522
void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
Alexandre Julliard's avatar
Alexandre Julliard committed
523
{
524 525
    RECT r = *lprc;
    UINT border = BDR_SUNKENOUTER;
Alexandre Julliard's avatar
Alexandre Julliard committed
526

527
    if (style & SBT_POPOUT)
528
        border = BDR_RAISEDOUTER;
529
    else if (style & SBT_NOBORDERS)
530
        border = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
531

532
    DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
Alexandre Julliard's avatar
Alexandre Julliard committed
533 534 535

    /* now draw text */
    if (text) {
536 537
        int oldbkmode = SetBkMode (hdc, TRANSPARENT);
        UINT align = DT_LEFT;
538 539
        int strCnt = 0;

540
        if (style & SBT_RTLREADING)
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
            FIXME("Unsupported RTL style!\n");
        r.left += 3;
        do {
            if (*text == '\t') {
                if (strCnt) {
                    DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
                    strCnt = 0;
                }
                if (align==DT_RIGHT) {
                    break;
                }
                align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
            } else {
                strCnt++;
            }
        } while(*text++);

        if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
559
	SetBkMode(hdc, oldbkmode);
Alexandre Julliard's avatar
Alexandre Julliard committed
560 561 562
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
563

Alexandre Julliard's avatar
Alexandre Julliard committed
564
/***********************************************************************
565
 * DrawStatusText  [COMCTL32.@]
566
 * DrawStatusTextA [COMCTL32.5]
Alexandre Julliard's avatar
Alexandre Julliard committed
567 568 569 570 571 572 573
 *
 * Draws text with borders, like in a status bar.
 *
 * PARAMS
 *     hdc   [I] handle to the window's display context
 *     lprc  [I] pointer to a rectangle
 *     text  [I] pointer to the text
574
 *     style [I] drawing style
Alexandre Julliard's avatar
Alexandre Julliard committed
575 576 577
 *
 * RETURNS
 *     No return value.
Alexandre Julliard's avatar
Alexandre Julliard committed
578
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
579

580
void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
Alexandre Julliard's avatar
Alexandre Julliard committed
581
{
582 583 584 585 586
    INT len;
    LPWSTR textW = NULL;

    if ( text ) {
	if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
587
	    if ( (textW = Alloc( len * sizeof(WCHAR) )) )
588 589 590 591
		MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
	}
    }
    DrawStatusTextW( hdc, lprc, textW, style );
592
    Free( textW );
Alexandre Julliard's avatar
Alexandre Julliard committed
593 594
}

Alexandre Julliard's avatar
Alexandre Julliard committed
595

Alexandre Julliard's avatar
Alexandre Julliard committed
596
/***********************************************************************
597
 * CreateStatusWindow  [COMCTL32.@]
598
 * CreateStatusWindowA [COMCTL32.6]
599 600
 *
 * Creates a status bar
Alexandre Julliard's avatar
Alexandre Julliard committed
601 602
 *
 * PARAMS
603 604
 *     style  [I] window style
 *     text   [I] pointer to the window text
Alexandre Julliard's avatar
Alexandre Julliard committed
605
 *     parent [I] handle to the parent window
606
 *     wid    [I] control id of the status bar
Alexandre Julliard's avatar
Alexandre Julliard committed
607 608
 *
 * RETURNS
609
 *     Success: handle to the status window
Alexandre Julliard's avatar
Alexandre Julliard committed
610
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
611
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
612

613
HWND WINAPI
614
CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
Alexandre Julliard's avatar
Alexandre Julliard committed
615
{
616 617
    return CreateWindowA(STATUSCLASSNAMEA, text, style,
			   CW_USEDEFAULT, CW_USEDEFAULT,
618
			   CW_USEDEFAULT, CW_USEDEFAULT,
Frank Richter's avatar
Frank Richter committed
619
			   parent, (HMENU)(DWORD_PTR)wid, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
620 621
}

Alexandre Julliard's avatar
Alexandre Julliard committed
622

Alexandre Julliard's avatar
Alexandre Julliard committed
623
/***********************************************************************
624 625 626
 * CreateStatusWindowW [COMCTL32.@]
 *
 * Creates a status bar control
Alexandre Julliard's avatar
Alexandre Julliard committed
627 628
 *
 * PARAMS
629 630
 *     style  [I] window style
 *     text   [I] pointer to the window text
631 632
 *     parent [I] handle to the parent window
 *     wid    [I] control id of the status bar
Alexandre Julliard's avatar
Alexandre Julliard committed
633 634
 *
 * RETURNS
635
 *     Success: handle to the status window
Alexandre Julliard's avatar
Alexandre Julliard committed
636
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
637
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
638

639
HWND WINAPI
640
CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
Alexandre Julliard's avatar
Alexandre Julliard committed
641
{
642 643 644
    return CreateWindowW(STATUSCLASSNAMEW, text, style,
			   CW_USEDEFAULT, CW_USEDEFAULT,
			   CW_USEDEFAULT, CW_USEDEFAULT,
Frank Richter's avatar
Frank Richter committed
645
			   parent, (HMENU)(DWORD_PTR)wid, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
646 647
}

Alexandre Julliard's avatar
Alexandre Julliard committed
648

649
/***********************************************************************
650 651 652
 * CreateUpDownControl [COMCTL32.16]
 *
 * Creates an up-down control
653 654
 *
 * PARAMS
655 656 657 658 659
 *     style  [I] window styles
 *     x      [I] horizontal position of the control
 *     y      [I] vertical position of the control
 *     cx     [I] with of the control
 *     cy     [I] height of the control
660
 *     parent [I] handle to the parent window
661 662 663 664 665 666
 *     id     [I] the control's identifier
 *     inst   [I] handle to the application's module instance
 *     buddy  [I] handle to the buddy window, can be NULL
 *     maxVal [I] upper limit of the control
 *     minVal [I] lower limit of the control
 *     curVal [I] current value of the control
Alexandre Julliard's avatar
Alexandre Julliard committed
667 668
 *
 * RETURNS
669
 *     Success: handle to the updown control
Alexandre Julliard's avatar
Alexandre Julliard committed
670
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
671
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
672

673 674 675 676
HWND WINAPI
CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
		     HWND parent, INT id, HINSTANCE inst,
		     HWND buddy, INT maxVal, INT minVal, INT curVal)
Alexandre Julliard's avatar
Alexandre Julliard committed
677
{
678
    HWND hUD =
679
	CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
Frank Richter's avatar
Frank Richter committed
680
			 parent, (HMENU)(DWORD_PTR)id, inst, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
681
    if (hUD) {
682 683 684
	SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
	SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
	SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
Alexandre Julliard's avatar
Alexandre Julliard committed
685 686 687
    }

    return hUD;
Alexandre Julliard's avatar
Alexandre Julliard committed
688 689 690 691
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
692 693
 * InitCommonControls [COMCTL32.17]
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
694
 * Registers the common controls.
Alexandre Julliard's avatar
Alexandre Julliard committed
695
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
696
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
697 698 699 700
 *     No parameters.
 *
 * RETURNS
 *     No return values.
Alexandre Julliard's avatar
Alexandre Julliard committed
701
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
702
 * NOTES
703 704
 *     This function is just a dummy - all the controls are registered at
 *     the DLL's initialization. See InitCommonContolsEx for details.
Alexandre Julliard's avatar
Alexandre Julliard committed
705 706 707
 */

VOID WINAPI
708
InitCommonControls (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
709 710 711 712 713
{
}


/***********************************************************************
714
 * InitCommonControlsEx [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
715
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
716
 * Registers the common controls.
Alexandre Julliard's avatar
Alexandre Julliard committed
717
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
718
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
719 720 721 722 723
 *     lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
724 725
 *
 * NOTES
726
 *     Probably all versions of comctl32 initializes the Win95 controls in DllMain
727
 *     during DLL initialization. Starting from comctl32 v5.82 all the controls
728 729 730 731 732 733 734
 *     are initialized there. We follow this behaviour and this function is just
 *     a dummy.
 *
 *     Note: when writing programs under Windows, if you don't call any function
 *     from comctl32 the linker may not link this DLL. If InitCommonControlsEx
 *     was the only comctl32 function you were calling and you remove it you may
 *     have a false impression that InitCommonControlsEx actually did something.
Alexandre Julliard's avatar
Alexandre Julliard committed
735
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
736

737
BOOL WINAPI
738
InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
Alexandre Julliard's avatar
Alexandre Julliard committed
739
{
740 741
    if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
        return FALSE;
742

743
    TRACE("(0x%08x)\n", lpInitCtrls->dwICC);
Alexandre Julliard's avatar
Alexandre Julliard committed
744
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
745
}
Alexandre Julliard's avatar
Alexandre Julliard committed
746 747 748


/***********************************************************************
749 750 751
 * CreateToolbarEx [COMCTL32.@]
 *
 * Creates a toolbar window.
Alexandre Julliard's avatar
Alexandre Julliard committed
752
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
753 754 755 756 757 758 759 760 761 762 763 764 765 766
 * PARAMS
 *     hwnd
 *     style
 *     wID
 *     nBitmaps
 *     hBMInst
 *     wBMID
 *     lpButtons
 *     iNumButtons
 *     dxButton
 *     dyButton
 *     dxBitmap
 *     dyBitmap
 *     uStructSize
Alexandre Julliard's avatar
Alexandre Julliard committed
767
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
768 769 770
 * RETURNS
 *     Success: handle to the tool bar control
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
771 772
 */

773 774 775 776 777
HWND WINAPI
CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
                 HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons,
                 INT iNumButtons, INT dxButton, INT dyButton,
                 INT dxBitmap, INT dyBitmap, UINT uStructSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
778
{
779 780 781
    HWND hwndTB;

    hwndTB =
782
        CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
Frank Richter's avatar
Frank Richter committed
783
                        hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
784 785 786
    if(hwndTB) {
	TBADDBITMAP tbab;

787
        SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
788

789 790
       /* set bitmap and button size */
       /*If CreateToolbarEx receives 0, windows sets default values*/
791
       if (dxBitmap < 0)
792
           dxBitmap = 16;
793 794 795 796 797
       if (dyBitmap < 0)
           dyBitmap = 16;
       if (dxBitmap == 0 || dyBitmap == 0)
           dxBitmap = dyBitmap = 16;
       SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
798

799 800 801 802 803 804 805
       if (dxButton < 0)
           dxButton = dxBitmap;
       if (dyButton < 0)
           dyButton = dyBitmap;
       /* TB_SETBUTTONSIZE -> TB_SETBITMAPSIZE bug introduced for Windows compatibility */
       if (dxButton != 0 && dyButton != 0)
            SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
806

Alexandre Julliard's avatar
Alexandre Julliard committed
807 808

	/* add bitmaps */
809
	if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
810
	{
811 812
	    tbab.hInst = hBMInst;
	    tbab.nID   = wBMID;
813

814
	    SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
815
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
816
	/* add buttons */
817
	if(iNumButtons > 0)
818
	SendMessageW (hwndTB, TB_ADDBUTTONSW,
819
			(WPARAM)iNumButtons, (LPARAM)lpButtons);
Alexandre Julliard's avatar
Alexandre Julliard committed
820 821
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
822
    return hwndTB;
Alexandre Julliard's avatar
Alexandre Julliard committed
823 824 825 826 827 828
}


/***********************************************************************
 * CreateMappedBitmap [COMCTL32.8]
 *
829 830
 * Loads a bitmap resource using a colour map.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
831
 * PARAMS
832 833 834 835 836
 *     hInstance  [I] Handle to the module containing the bitmap.
 *     idBitmap   [I] The bitmap resource ID.
 *     wFlags     [I] CMB_MASKED for using bitmap as a mask or 0 for normal.
 *     lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours).
 *     iNumMaps   [I] Number of COLORMAP's pointed to by lpColorMap.
Alexandre Julliard's avatar
Alexandre Julliard committed
837 838
 *
 * RETURNS
839
 *     Success: handle to the new bitmap
Alexandre Julliard's avatar
Alexandre Julliard committed
840
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
841 842
 */

843
HBITMAP WINAPI
Frank Richter's avatar
Frank Richter committed
844
CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
845
		    LPCOLORMAP lpColorMap, INT iNumMaps)
Alexandre Julliard's avatar
Alexandre Julliard committed
846
{
847 848
    HGLOBAL hglb;
    HRSRC hRsrc;
849 850
    const BITMAPINFOHEADER *lpBitmap;
    LPBITMAPINFOHEADER lpBitmapInfo;
851
    UINT nSize, nColorTableSize, iColor;
852
    RGBQUAD *pColorTable;
853
    INT i, iMaps, nWidth, nHeight;
854 855
    HDC hdcScreen;
    HBITMAP hbm;
Alexandre Julliard's avatar
Alexandre Julliard committed
856
    LPCOLORMAP sysColorMap;
857
    COLORREF cRef;
Alexandre Julliard's avatar
Alexandre Julliard committed
858 859 860 861 862 863 864 865 866
    COLORMAP internalColorMap[4] =
	{{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};

    /* initialize pointer to colortable and default color table */
    if (lpColorMap) {
	iMaps = iNumMaps;
	sysColorMap = lpColorMap;
    }
    else {
867 868 869 870
	internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
	internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
	internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
	internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
Alexandre Julliard's avatar
Alexandre Julliard committed
871 872 873
	iMaps = 4;
	sysColorMap = (LPCOLORMAP)internalColorMap;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
874

875
    hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
Alexandre Julliard's avatar
Alexandre Julliard committed
876 877
    if (hRsrc == 0)
	return 0;
878
    hglb = LoadResource (hInstance, hRsrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
879 880
    if (hglb == 0)
	return 0;
881
    lpBitmap = LockResource (hglb);
Alexandre Julliard's avatar
Alexandre Julliard committed
882
    if (lpBitmap == NULL)
Alexandre Julliard's avatar
Alexandre Julliard committed
883
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
884

885 886 887 888 889 890
    if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
        nColorTableSize = lpBitmap->biClrUsed;
    else if (lpBitmap->biBitCount <= 8)	
        nColorTableSize = (1 << lpBitmap->biBitCount);
    else
        nColorTableSize = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
891
    nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
892
    lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
Alexandre Julliard's avatar
Alexandre Julliard committed
893
    if (lpBitmapInfo == NULL)
Alexandre Julliard's avatar
Alexandre Julliard committed
894
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
895 896
    RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);

897
    pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
Alexandre Julliard's avatar
Alexandre Julliard committed
898 899 900

    for (iColor = 0; iColor < nColorTableSize; iColor++) {
	for (i = 0; i < iMaps; i++) {
901 902 903 904
            cRef = RGB(pColorTable[iColor].rgbRed,
                       pColorTable[iColor].rgbGreen,
                       pColorTable[iColor].rgbBlue);
	    if ( cRef  == sysColorMap[i].from) {
Alexandre Julliard's avatar
Alexandre Julliard committed
905 906 907 908 909 910 911
#if 0
		if (wFlags & CBS_MASKED) {
		    if (sysColorMap[i].to != COLOR_BTNTEXT)
			pColorTable[iColor] = RGB(255, 255, 255);
		}
		else
#endif
912 913 914
                    pColorTable[iColor].rgbBlue  = GetBValue(sysColorMap[i].to);
                    pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
                    pColorTable[iColor].rgbRed   = GetRValue(sysColorMap[i].to);
Alexandre Julliard's avatar
Alexandre Julliard committed
915 916 917 918
		break;
	    }
	}
    }
919 920
    nWidth  = lpBitmapInfo->biWidth;
    nHeight = lpBitmapInfo->biHeight;
921
    hdcScreen = GetDC (NULL);
922
    hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
Alexandre Julliard's avatar
Alexandre Julliard committed
923
    if (hbm) {
924 925
	HDC hdcDst = CreateCompatibleDC (hdcScreen);
	HBITMAP hbmOld = SelectObject (hdcDst, hbm);
926
	const BYTE *lpBits = (const BYTE *)(lpBitmap + 1);
927
	lpBits += nColorTableSize * sizeof(RGBQUAD);
928
	StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
Alexandre Julliard's avatar
Alexandre Julliard committed
929 930
		         lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
		         SRCCOPY);
931 932
	SelectObject (hdcDst, hbmOld);
	DeleteDC (hdcDst);
Alexandre Julliard's avatar
Alexandre Julliard committed
933
    }
934
    ReleaseDC (NULL, hdcScreen);
935
    GlobalFree (lpBitmapInfo);
936
    FreeResource (hglb);
Alexandre Julliard's avatar
Alexandre Julliard committed
937 938

    return hbm;
Alexandre Julliard's avatar
Alexandre Julliard committed
939
}
Alexandre Julliard's avatar
Alexandre Julliard committed
940 941 942


/***********************************************************************
943 944 945
 * CreateToolbar [COMCTL32.7]
 *
 * Creates a toolbar control.
Alexandre Julliard's avatar
Alexandre Julliard committed
946
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
947 948 949 950 951 952 953 954 955
 * PARAMS
 *     hwnd
 *     style
 *     wID
 *     nBitmaps
 *     hBMInst
 *     wBMID
 *     lpButtons
 *     iNumButtons
Alexandre Julliard's avatar
Alexandre Julliard committed
956
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
957 958 959
 * RETURNS
 *     Success: handle to the tool bar control
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
960
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
961 962
 * NOTES
 *     Do not use this functions anymore. Use CreateToolbarEx instead.
Alexandre Julliard's avatar
Alexandre Julliard committed
963 964
 */

965 966 967
HWND WINAPI
CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
	       HINSTANCE hBMInst, UINT wBMID,
968
	       LPCTBBUTTON lpButtons,INT iNumButtons)
Alexandre Julliard's avatar
Alexandre Julliard committed
969 970
{
    return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
971 972
			    hBMInst, wBMID, lpButtons,
			    iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
Alexandre Julliard's avatar
Alexandre Julliard committed
973 974
}

Alexandre Julliard's avatar
Alexandre Julliard committed
975 976

/***********************************************************************
977
 * DllGetVersion [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
978
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
979
 * Retrieves version information of the 'COMCTL32.DLL'
Alexandre Julliard's avatar
Alexandre Julliard committed
980 981
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
982
 *     pdvi [O] pointer to version information structure.
Alexandre Julliard's avatar
Alexandre Julliard committed
983
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
984
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
985 986
 *     Success: S_OK
 *     Failure: E_INVALIDARG
Alexandre Julliard's avatar
Alexandre Julliard committed
987 988 989
 *
 * NOTES
 *     Returns version of a comctl32.dll from IE4.01 SP1.
Alexandre Julliard's avatar
Alexandre Julliard committed
990 991
 */

992
HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
Alexandre Julliard's avatar
Alexandre Julliard committed
993
{
Alexandre Julliard's avatar
Alexandre Julliard committed
994
    if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
995
        WARN("wrong DLLVERSIONINFO size from app\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
996
	return E_INVALIDARG;
Alexandre Julliard's avatar
Alexandre Julliard committed
997 998
    }

Gerard Patel's avatar
Gerard Patel committed
999 1000
    pdvi->dwMajorVersion = COMCTL32_VERSION;
    pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR;
1001 1002
    pdvi->dwBuildNumber = 2919;
    pdvi->dwPlatformID = 6304;
Alexandre Julliard's avatar
Alexandre Julliard committed
1003

1004
    TRACE("%u.%u.%u.%u\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1005 1006 1007 1008
	   pdvi->dwMajorVersion, pdvi->dwMinorVersion,
	   pdvi->dwBuildNumber, pdvi->dwPlatformID);

    return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1009
}
1010

1011
/***********************************************************************
1012
 *		DllInstall (COMCTL32.@)
1013 1014 1015 1016 1017 1018
 *
 * Installs the ComCtl32 DLL.
 *
 * RETURNS
 *     Success: S_OK
 *     Failure: A HRESULT error
1019
 */
1020
HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
1021
{
1022 1023 1024
    TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
    if (!create_manifest( bInstall )) return HRESULT_FROM_WIN32(GetLastError());
    return S_OK;
1025
}
1026 1027

/***********************************************************************
1028
 * _TrackMouseEvent [COMCTL32.@]
1029 1030 1031
 *
 * Requests notification of mouse events
 *
1032 1033 1034 1035 1036 1037 1038 1039
 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
 * to the hwnd specified in the ptme structure.  After the event message
 * is posted to the hwnd, the entry in the queue is removed.
 *
 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
 * immediately and the TME_LEAVE flag being ignored.
 *
1040 1041 1042 1043 1044 1045 1046
 * PARAMS
 *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
 *
 * RETURNS
 *     Success: non-zero
 *     Failure: zero
 *
1047 1048
 * IMPLEMENTATION moved to USER32.TrackMouseEvent
 *
1049 1050 1051 1052 1053
 */

BOOL WINAPI
_TrackMouseEvent (TRACKMOUSEEVENT *ptme)
{
1054
    return TrackMouseEvent (ptme);
1055
}
1056 1057

/*************************************************************************
1058
 * GetMUILanguage [COMCTL32.@]
1059
 *
1060
 * Returns the user interface language in use by the current process.
1061
 *
1062 1063
 * RETURNS
 *      Language ID in use by the current process.
1064 1065 1066 1067 1068 1069 1070 1071
 */
LANGID WINAPI GetMUILanguage (VOID)
{
    return COMCTL32_uiLang;
}


/*************************************************************************
1072
 * InitMUILanguage [COMCTL32.@]
1073
 *
1074
 * Sets the user interface language to be used by the current process.
1075
 *
1076 1077
 * RETURNS
 *      Nothing.
1078 1079 1080 1081 1082
 */
VOID WINAPI InitMUILanguage (LANGID uiLang)
{
   COMCTL32_uiLang = uiLang;
}
1083 1084


1085
/***********************************************************************
1086
 * SetWindowSubclass [COMCTL32.410]
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
 *
 * Starts a window subclass
 *
 * PARAMS
 *     hWnd [in] handle to window subclass.
 *     pfnSubclass [in] Pointer to new window procedure.
 *     uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
 *     dwRef [in] Reference data to pass to window procedure.
 *
 * RETURNS
 *     Success: non-zero
 *     Failure: zero
 *
 * BUGS
 *     If an application manually subclasses a window after subclassing it with
1102
 *     this API and then with this API again, then none of the previous 
1103
 *     subclasses get called or the original window procedure.
1104
 */
1105

1106 1107 1108 1109
BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
                        UINT_PTR uIDSubclass, DWORD_PTR dwRef)
{
   LPSUBCLASS_INFO stack;
1110
   LPSUBCLASSPROCS proc;
1111

1112
   TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
1113 1114 1115 1116 1117 1118 1119

   /* Since the window procedure that we set here has two additional arguments,
    * we can't simply set it as the new window procedure of the window. So we
    * set our own window procedure and then calculate the other two arguments
    * from there. */

   /* See if we have been called for this window */
1120
   stack = GetPropW (hWnd, COMCTL32_wSubclass);
1121 1122
   if (!stack) {
      /* allocate stack */
1123
      stack = Alloc (sizeof(SUBCLASS_INFO));
1124
      if (!stack) {
1125
         ERR ("Failed to allocate our Subclassing stack\n");
1126 1127
         return FALSE;
      }
1128
      SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack);
1129 1130 1131

      /* set window procedure to our own and save the current one */
      if (IsWindowUnicode (hWnd))
1132 1133
         stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
                                                   (DWORD_PTR)COMCTL32_SubclassProc);
1134
      else
1135 1136
         stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC,
                                                   (DWORD_PTR)COMCTL32_SubclassProc);
1137
   }
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
   else {
      /* Check to see if we have called this function with the same uIDSubClass
       * and pfnSubclass */
      proc = stack->SubclassProcs;
      while (proc) {
         if ((proc->id == uIDSubclass) &&
            (proc->subproc == pfnSubclass)) {
            proc->ref = dwRef;
            return TRUE;
         }
         proc = proc->next;
1149
      }
1150 1151
   }
   
1152
   proc = Alloc(sizeof(SUBCLASSPROCS));
1153 1154 1155
   if (!proc) {
      ERR ("Failed to allocate subclass entry in stack\n");
      if (IsWindowUnicode (hWnd))
1156
         SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1157
      else
1158
         SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1159
      Free (stack);
1160
      RemovePropW( hWnd, COMCTL32_wSubclass );
1161 1162 1163
      return FALSE;
   }
   
1164 1165 1166 1167 1168 1169
   proc->subproc = pfnSubclass;
   proc->ref = dwRef;
   proc->id = uIDSubclass;
   proc->next = stack->SubclassProcs;
   stack->SubclassProcs = proc;

1170 1171 1172 1173 1174
   return TRUE;
}


/***********************************************************************
1175
 * GetWindowSubclass [COMCTL32.411]
1176 1177 1178 1179 1180 1181
 *
 * Gets the Reference data from a subclass.
 *
 * PARAMS
 *     hWnd [in] Handle to window which were subclassing
 *     pfnSubclass [in] Pointer to the subclass procedure
Jon Griffiths's avatar
Jon Griffiths committed
1182
 *     uID [in] Unique indentifier of the subclassing procedure
1183 1184 1185
 *     pdwRef [out] Pointer to the reference data
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
1186 1187
 *     Success: Non-zero
 *     Failure: 0
1188
 */
1189

1190 1191 1192
BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
                              UINT_PTR uID, DWORD_PTR *pdwRef)
{
1193 1194
   const SUBCLASS_INFO *stack;
   const SUBCLASSPROCS *proc;
1195

1196
   TRACE ("(%p, %p, %lx, %p)\n", hWnd, pfnSubclass, uID, pdwRef);
1197 1198

   /* See if we have been called for this window */
1199
   stack = GetPropW (hWnd, COMCTL32_wSubclass);
1200 1201 1202
   if (!stack)
      return FALSE;

1203 1204 1205 1206 1207
   proc = stack->SubclassProcs;
   while (proc) {
      if ((proc->id == uID) &&
         (proc->subproc == pfnSubclass)) {
         *pdwRef = proc->ref;
1208 1209
         return TRUE;
      }
1210 1211
      proc = proc->next;
   }
1212 1213 1214 1215 1216 1217

   return FALSE;
}


/***********************************************************************
1218
 * RemoveWindowSubclass [COMCTL32.412]
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
 *
 * Removes a window subclass.
 *
 * PARAMS
 *     hWnd [in] Handle to the window were subclassing
 *     pfnSubclass [in] Pointer to the subclass procedure
 *     uID [in] Unique identifier of this subclass
 *
 * RETURNS
 *     Success: non-zero
 *     Failure: zero
 */
1231

1232 1233 1234
BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
{
   LPSUBCLASS_INFO stack;
1235 1236 1237
   LPSUBCLASSPROCS prevproc = NULL;
   LPSUBCLASSPROCS proc;
   BOOL ret = FALSE;
1238

1239
   TRACE ("(%p, %p, %lx)\n", hWnd, pfnSubclass, uID);
1240 1241

   /* Find the Subclass to remove */
1242
   stack = GetPropW (hWnd, COMCTL32_wSubclass);
1243 1244 1245
   if (!stack)
      return FALSE;

1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
   proc = stack->SubclassProcs;
   while (proc) {
      if ((proc->id == uID) &&
         (proc->subproc == pfnSubclass)) {
         
         if (!prevproc)
            stack->SubclassProcs = proc->next;
         else
            prevproc->next = proc->next;
          
         if (stack->stackpos == proc)
            stack->stackpos = stack->stackpos->next;
            
1259
         Free (proc);
1260 1261 1262 1263 1264 1265 1266 1267
         ret = TRUE;
         break;
      }
      prevproc = proc;
      proc = proc->next;
   }
   
   if (!stack->SubclassProcs && !stack->running) {
1268
      TRACE("Last Subclass removed, cleaning up\n");
1269
      /* clean up our heap and reset the original window procedure */
1270
      if (IsWindowUnicode (hWnd))
1271
         SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1272
      else
1273
         SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1274
      Free (stack);
1275
      RemovePropW( hWnd, COMCTL32_wSubclass );
1276
   }
1277 1278 1279
   
   return ret;
}
1280

1281 1282 1283 1284 1285 1286
/***********************************************************************
 * COMCTL32_SubclassProc (internal)
 *
 * Window procedure for all subclassed windows. 
 * Saves the current subclassing stack position to support nested messages
 */
1287
static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1288 1289 1290 1291 1292
{
   LPSUBCLASS_INFO stack;
   LPSUBCLASSPROCS proc;
   LRESULT ret;
    
1293
   TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1294

1295
   stack = GetPropW (hWnd, COMCTL32_wSubclass);
1296 1297 1298 1299 1300 1301 1302 1303
   if (!stack) {
      ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
      return 0;
   }
    
   /* Save our old stackpos to properly handle nested messages */
   proc = stack->stackpos;
   stack->stackpos = stack->SubclassProcs;
1304
   stack->running++;
1305
   ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
1306
   stack->running--;
1307 1308
   stack->stackpos = proc;
    
1309
   if (!stack->SubclassProcs && !stack->running) {
1310
      TRACE("Last Subclass removed, cleaning up\n");
1311
      /* clean up our heap and reset the original window procedure */
1312
      if (IsWindowUnicode (hWnd))
1313
         SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1314
      else
1315
         SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
1316
      Free (stack);
1317
      RemovePropW( hWnd, COMCTL32_wSubclass );
1318 1319
   }
   return ret;
1320 1321 1322
}

/***********************************************************************
1323
 * DefSubclassProc [COMCTL32.413]
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
 *
 * Calls the next window procedure (ie. the one before this subclass)
 *
 * PARAMS
 *     hWnd [in] The window that we're subclassing
 *     uMsg [in] Message
 *     wParam [in] WPARAM
 *     lParam [in] LPARAM
 *
 * RETURNS
 *     Success: non-zero
 *     Failure: zero
 */
1337

1338 1339 1340 1341
LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   LPSUBCLASS_INFO stack;
   LRESULT ret;
1342
   
1343
   TRACE ("(%p, 0x%08x, 0x%08lx, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
1344 1345

   /* retrieve our little stack from the Properties */
1346
   stack = GetPropW (hWnd, COMCTL32_wSubclass);
1347
   if (!stack) {
1348
      ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
1349 1350 1351
      return 0;
   }

1352 1353
   /* If we are at the end of stack then we have to call the original
    * window procedure */
1354
   if (!stack->stackpos) {
1355
      if (IsWindowUnicode (hWnd))
1356
         ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
1357
      else
1358 1359
         ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
   } else {
1360
      const SUBCLASSPROCS *proc = stack->stackpos;
1361
      stack->stackpos = stack->stackpos->next; 
1362
      /* call the Subclass procedure from the stack */
1363 1364
      ret = proc->subproc (hWnd, uMsg, wParam, lParam,
            proc->id, proc->ref);
1365 1366 1367 1368 1369 1370
   }

   return ret;
}


1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
/***********************************************************************
 * COMCTL32_CreateToolTip [NOT AN API]
 *
 * Creates a tooltip for the control specified in hwnd and does all
 * necessary setup and notifications.
 *
 * PARAMS
 *     hwndOwner [I] Handle to the window that will own the tool tip.
 *
 * RETURNS
 *     Success: Handle of tool tip window.
 *     Failure: NULL
 */
1384

1385 1386 1387 1388 1389
HWND
COMCTL32_CreateToolTip(HWND hwndOwner)
{
    HWND hwndToolTip;

1390
    hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1391 1392 1393 1394 1395 1396 1397 1398
				  CW_USEDEFAULT, CW_USEDEFAULT,
				  CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
				  0, 0, 0);

    /* Send NM_TOOLTIPSCREATED notification */
    if (hwndToolTip)
    {
	NMTOOLTIPSCREATED nmttc;
1399 1400 1401
        /* true owner can be different if hwndOwner is a child window */
        HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
        nmttc.hdr.hwndFrom = hwndTrueOwner;
1402
        nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
1403 1404 1405
	nmttc.hdr.code = NM_TOOLTIPSCREATED;
	nmttc.hwndToolTips = hwndToolTip;

1406
       SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
1407
                    (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
1408
		    (LPARAM)&nmttc);
1409 1410 1411 1412
    }

    return hwndToolTip;
}
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426


/***********************************************************************
 * COMCTL32_RefreshSysColors [NOT AN API]
 *
 * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
 * refresh the color values in the color structure
 *
 * PARAMS
 *     none
 *
 * RETURNS
 *     none
 */
1427

1428 1429 1430 1431 1432 1433 1434 1435 1436
VOID
COMCTL32_RefreshSysColors(void)
{
    comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
    comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
    comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
    comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
    comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
    comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
1437
    comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
    comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
    comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
    comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
    comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
    comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
    comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
    comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
    comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
    comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
    comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
}
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501

/***********************************************************************
 * COMCTL32_DrawInsertMark [NOT AN API]
 *
 * Draws an insertion mark (which looks similar to an 'I').
 *
 * PARAMS
 *     hDC           [I] Device context to draw onto.
 *     lpRect        [I] Co-ordinates of insertion mark.
 *     clrInsertMark [I] Colour of the insertion mark.
 *     bHorizontal   [I] True if insert mark should be drawn horizontally,
 *                       vertical otherwise.
 *
 * RETURNS
 *     none
 *
 * NOTES
 *     Draws up to but not including the bottom co-ordinate when drawing
 *     vertically or the right co-ordinate when horizontal.
 */
void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
{
    HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
    HPEN hOldPen;
    static const DWORD adwPolyPoints[] = {4,4,4};
    LONG lCentre = (bHorizontal ? 
        lpRect->top + (lpRect->bottom - lpRect->top)/2 : 
        lpRect->left + (lpRect->right - lpRect->left)/2);
    LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
    LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
    const POINT aptInsertMark[] =
    {
        /* top (V) or left (H) arrow */
        {lCentre    , l1 + 2},
        {lCentre - 2, l1    },
        {lCentre + 3, l1    },
        {lCentre + 1, l1 + 2},
        /* middle line */
        {lCentre    , l2 - 2},
        {lCentre    , l1 - 1},
        {lCentre + 1, l1 - 1},
        {lCentre + 1, l2 - 2},
        /* bottom (V) or right (H) arrow */
        {lCentre    , l2 - 3},
        {lCentre - 2, l2 - 1},
        {lCentre + 3, l2 - 1},
        {lCentre + 1, l2 - 3},
    };
    hOldPen = SelectObject(hDC, hPen);
    PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
    SelectObject(hDC, hOldPen);
    DeleteObject(hPen);
}
1502

1503 1504 1505
/***********************************************************************
 * COMCTL32_EnsureBitmapSize [internal]
 *
1506 1507
 * If needed, enlarge the bitmap so that the width is at least cxMinWidth and
 * the height is at least cyMinHeight. If the bitmap already has these
1508 1509 1510 1511
 * dimensions nothing changes.
 *
 * PARAMS
 *     hBitmap       [I/O] Bitmap to modify. The handle may change
1512
 *     cxMinWidth    [I]   If the width of the bitmap is smaller, then it will
1513
 *                         be enlarged to this value
1514
 *     cyMinHeight   [I]   If the height of the bitmap is smaller, then it will
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
 *                         be enlarged to this value
 *     cyBackground  [I]   The color with which the new area will be filled
 *
 * RETURNS
 *     none
 */
void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
{
    int cxNew, cyNew;
    BITMAP bmp;
    HBITMAP hNewBitmap;
    HBITMAP hNewDCBitmap, hOldDCBitmap;
    HBRUSH hNewDCBrush;
    HDC hdcNew, hdcOld;

    if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
        return;
    cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
    cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
    if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
        return;

    hdcNew = CreateCompatibleDC(NULL);
    hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
    hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
    hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));

    hdcOld = CreateCompatibleDC(NULL);
    hOldDCBitmap = SelectObject(hdcOld, *pBitmap);

    BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
    if (bmp.bmWidth < cxMinWidth)
        PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
    if (bmp.bmHeight < cyMinHeight)
        PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
    if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
        PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);

    SelectObject(hdcNew, hNewDCBitmap);
    DeleteObject(SelectObject(hdcNew, hNewDCBrush));
    DeleteDC(hdcNew);
    SelectObject(hdcOld, hOldDCBitmap);
    DeleteDC(hdcOld);

    DeleteObject(*pBitmap);    
    *pBitmap = hNewBitmap;
    return;
}

1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
{
    HDC hdc = GetDC(NULL);
    HFONT hOldFont;

    hOldFont = SelectObject(hdc, hFont);
    GetTextMetricsW(hdc, ptm);
    SelectObject(hdc, hOldFont);
    ReleaseDC(NULL, hdc);
}

1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
#ifndef OCM__BASE      /* avoid including olectl.h */
#define OCM__BASE (WM_USER+0x1c00)
#endif

/***********************************************************************
 * COMCTL32_IsReflectedMessage [internal]
 *
 * Some parents reflect notify messages - for some messages sent by the child,
 * they send it back with the message code increased by OCM__BASE (0x2000).
 * This allows better subclassing of controls. We don't need to handle such
 * messages but we don't want to print ERRs for them, so this helper function
 * identifies them.
 *
 * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
 * colision with defined CCM_ codes.
 */
BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
{
    switch (uMsg)
    {
        case OCM__BASE + WM_COMMAND:
        case OCM__BASE + WM_CTLCOLORBTN:
        case OCM__BASE + WM_CTLCOLOREDIT:
        case OCM__BASE + WM_CTLCOLORDLG:
        case OCM__BASE + WM_CTLCOLORLISTBOX:
        case OCM__BASE + WM_CTLCOLORMSGBOX:
        case OCM__BASE + WM_CTLCOLORSCROLLBAR:
        case OCM__BASE + WM_CTLCOLORSTATIC:
        case OCM__BASE + WM_DRAWITEM:
        case OCM__BASE + WM_MEASUREITEM:
        case OCM__BASE + WM_DELETEITEM:
        case OCM__BASE + WM_VKEYTOITEM:
        case OCM__BASE + WM_CHARTOITEM:
        case OCM__BASE + WM_COMPAREITEM:
        case OCM__BASE + WM_HSCROLL:
        case OCM__BASE + WM_VSCROLL:
        case OCM__BASE + WM_PARENTNOTIFY:
        case OCM__BASE + WM_NOTIFY:
            return TRUE;
        default:
            return FALSE;
    }
}

1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
/***********************************************************************
 * MirrorIcon [COMCTL32.414]
 *
 * Mirrors an icon so that it will appear correctly on a mirrored DC.
 *
 * PARAMS
 *     phicon1 [I/O] Icon.
 *     phicon2 [I/O] Icon.
 *
 * RETURNS
 *     Success: TRUE.
 *     Failure: FALSE.
 */
BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
{
    FIXME("(%p, %p): stub\n", phicon1, phicon2);
    return FALSE;
}

static inline int IsDelimiter(WCHAR c)
{
    switch(c)
    {
	case '/':
	case '\\':
	case '.':
	case ' ':
	    return TRUE;
    }
    return FALSE;
}

1651
static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
{
    if (code == WB_ISDELIMITER)
        return IsDelimiter(lpch[ichCurrent]);
    else
    {
        int dir = (code == WB_LEFT) ? -1 : 1;
        for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
            if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
    }
    return ichCurrent;
}

/***********************************************************************
 * SetPathWordBreakProc [COMCTL32.384]
 *
 * Sets the word break procedure for an edit control to one that understands
 * paths so that the user can jump over directories.
 *
 * PARAMS
 *     hwnd [I] Handle to edit control.
 *     bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
 *
 * RETURNS
 *     Result from EM_SETWORDBREAKPROC message.
 */
LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
{
    return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
        (LPARAM)(bSet ? PathWordBreakProc : NULL));
}
1682 1683 1684 1685 1686 1687

/***********************************************************************
 * DrawShadowText [COMCTL32.@]
 *
 * Draw text with shadow.
 */
1688
int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *rect, DWORD dwFlags,
1689 1690
                          COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
{
1691
    FIXME("(%p, %s, %d, %p, %d, 0x%08x, 0x%08x, %d, %d): stub\n", hdc, debugstr_w(pszText), cch, rect, dwFlags,
1692
                                                                  crText, crShadow, ixOffset, iyOffset);
1693
    return DrawTextW(hdc, pszText, cch, rect, DT_LEFT);
1694
}