Filewatcher File Search
FTP Search
  
Directory (beta)
  
Content Search (beta)
   
pkg://wine-981025-1.src.rpm:2548475/Wine-981025.tar.gz  info  downloads

wine-981025/ 40755    771    771           0  6614657101  12362 5ustar  julliardjulliardwine-981025/dlls/ 40755    771    771           0  6614657075  13332 5ustar  julliardjulliardwine-981025/dlls/.cvsignore100644    771    771          11  6605734113  15344 0ustar  julliardjulliardMakefile
wine-981025/dlls/Makefile.in100644    771    771         730  6610163100  15425 0ustar  julliardjulliardSUBDIRS = \
	comctl32 \
	imagehlp \
	msacm \
	msacm32 \
	psapi \
	shell32 \
	winaspi \
	wnaspi32

all: $(SUBDIRS)

$(SUBDIRS): dummy
	@cd $@; $(MAKE)

depend:
	for i in $(SUBDIRS); do (cd $$i && $(MAKE) depend) || exit 1; done

install:
	for i in $(SUBDIRS); do (cd $$i && $(MAKE) install) || exit 1; done

uninstall:
	for i in $(SUBDIRS); do (cd $$i && $(MAKE) uninstall) || exit 1; done

clean:
	for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean) || exit 1; done

dummy:
wine-981025/dlls/comctl32/ 40755    771    771           0  6614657075  14760 5ustar  julliardjulliardwine-981025/dlls/comctl32/.cvsignore100644    771    771          11  6605734127  16777 0ustar  julliardjulliardMakefile
wine-981025/dlls/comctl32/Makefile.in100644    771    771         724  6610127773  17076 0ustar  julliardjulliardDEFS      = @DLLFLAGS@ -D__WINE__
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR    = @srcdir@
VPATH     = @srcdir@
MODULE    = comctl32

C_SRCS = \
	animate.c \
	comboex.c \
	comctl32undoc.c \
	commctrl.c \
	header.c \
	hotkey.c \
	imagelist.c \
	ipaddress.c \
	listview.c \
	nativefont.c \
	pager.c \
	progress.c \
	rebar.c \
	status.c \
	tab.c \
	toolbar.c \
	tooltips.c \
	trackbar.c \
	treeview.c \
	updown.c

all: $(MODULE).o

@MAKE_RULES@

### Dependencies:
wine-981025/dlls/comctl32/animate.c100644    771    771       15056  6614330267  16655 0ustar  julliardjulliard/*
 * Animation control
 *
 * Copyright 1998 Eric Kohl
 *
 * NOTES
 *   This is just a dummy control. An author is needed! Any volunteers?
 *   I will only improve this control once in a while.
 *     Eric <ekohl@abo.rhein-zeitung.de>
 *
 * TODO:
 *   - All messages.
 *   - All notifications.
 */

#include "windows.h"
#include "winnt.h"
#include "winbase.h"
#include "commctrl.h"
#include "animate.h"
#include "win.h"
#include "debug.h"


#define ANIMATE_GetInfoPtr(wndPtr) ((ANIMATE_INFO *)wndPtr->wExtra[0])


static BOOL32
ANIMATE_LoadRes32A (ANIMATE_INFO *infoPtr, HINSTANCE32 hInst, LPSTR lpName)
{
    HRSRC32 hrsrc;
    HGLOBAL32 handle;

    hrsrc = FindResource32A (hInst, lpName, "AVI");
    if (!hrsrc)
	return FALSE;

    handle = LoadResource32 (hInst, hrsrc);
    if (!handle)
	return FALSE;

    infoPtr->lpAvi = LockResource32 (handle);
    if (!infoPtr->lpAvi)
	return FALSE;

    return TRUE;
}


static BOOL32
ANIMATE_LoadFile32A (ANIMATE_INFO *infoPtr, LPSTR lpName)
{
    HANDLE32 handle;

    infoPtr->hFile =
	CreateFile32A (lpName, GENERIC_READ, 0, NULL, OPEN_EXISTING,
		       FILE_ATTRIBUTE_NORMAL, 0);
    if (!infoPtr->hFile)
	return FALSE;

    handle =
	CreateFileMapping32A (infoPtr->hFile, NULL, PAGE_READONLY | SEC_COMMIT,
			      0, 0, NULL);
    if (!handle) {
	CloseHandle (infoPtr->hFile);
	infoPtr->hFile = 0;
	return FALSE;
    }

    infoPtr->lpAvi = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, 0);
    if (!infoPtr->lpAvi) {
	CloseHandle (infoPtr->hFile);
	infoPtr->hFile = 0;
	return FALSE;
    }

    return TRUE;
}


static VOID
ANIMATE_Free (ANIMATE_INFO *infoPtr)
{
    if (infoPtr->hFile) {
	UnmapViewOfFile (infoPtr->lpAvi);
	CloseHandle (infoPtr->hFile);
	infoPtr->lpAvi = NULL;
    }
    else {
	GlobalFree32 (infoPtr->lpAvi);
	infoPtr->lpAvi = NULL;
    }
}


static VOID
ANIMATE_GetAviInfo (infoPtr)
{


}


static LRESULT
ANIMATE_Open32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(wndPtr);
    HINSTANCE32 hInstance = (HINSTANCE32)wParam;

    ANIMATE_Free (infoPtr);

    if (!lParam) {
	TRACE (animate, "closing avi!\n");
	return TRUE;
    }
    
    if (HIWORD(lParam)) {
	FIXME (animate, "(\"%s\") empty stub!\n", (LPSTR)lParam);

	if (ANIMATE_LoadRes32A (infoPtr, hInstance, (LPSTR)lParam)) {

	    FIXME (animate, "AVI resource found!\n");

	}
	else {
	    FIXME (animate, "No AVI resource found!\n");
	    if (ANIMATE_LoadFile32A (infoPtr, (LPSTR)lParam)) {
		FIXME (animate, "AVI file found!\n");
	    }
	    else {
		FIXME (animate, "No AVI file found!\n");
		return FALSE;
	    }
	}
    }
    else {
	FIXME (animate, "(%u) empty stub!\n", (WORD)LOWORD(lParam));

	if (ANIMATE_LoadRes32A (infoPtr, hInstance,
				MAKEINTRESOURCE32A((INT32)lParam))) {
	    FIXME (animate, "AVI resource found!\n");
	}
	else {
	    FIXME (animate, "No AVI resource found!\n");
	    return FALSE;
	}
    }

    ANIMATE_GetAviInfo (infoPtr);

    return TRUE;
}


// << ANIMATE_Open32W >>


static LRESULT
ANIMATE_Play (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(wndPtr);
    INT32 nFrom   = (INT32)LOWORD(lParam);
    INT32 nTo     = (INT32)HIWORD(lParam);
    INT32 nRepeat = (INT32)wParam;

#if 0
    /* nothing opened */
    if (...)
	return FALSE;
#endif
    
    if (nRepeat == -1) {

	FIXME (animate, "(loop from=%d to=%d) empty stub!\n",
	       nFrom, nTo);

    }
    else {

	FIXME (animate, "(repeat=%d from=%d to=%d) empty stub!\n",
	       nRepeat, nFrom, nTo);

    }


    return TRUE;
}


static LRESULT
ANIMATE_Stop (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(wndPtr);

#if 0
    /* nothing opened */
    if (...)
	return FALSE;
#endif
    
    return TRUE;
}



static LRESULT
ANIMATE_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    ANIMATE_INFO *infoPtr;

    /* allocate memory for info structure */
    infoPtr = (ANIMATE_INFO *)COMCTL32_Alloc (sizeof(ANIMATE_INFO));
    wndPtr->wExtra[0] = (DWORD)infoPtr;

    if (infoPtr == NULL) {
	ERR (animate, "could not allocate info memory!\n");
	return 0;
    }

    if ((ANIMATE_INFO*)wndPtr->wExtra[0] != infoPtr) {
	ERR (animate, "pointer assignment error!\n");
	return 0;
    }

    /* set default settings */


    return 0;
}


static LRESULT
ANIMATE_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(wndPtr);


    /* free avi data */
    ANIMATE_Free (infoPtr);

    /* free animate info data */
    COMCTL32_Free (infoPtr);

    return 0;
}


#if 0
static LRESULT
ANIMATE_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    ANIMATE_INFO *infoPtr = ANIMATE_GetInfoPtr(wndPtr);
/*
    HBRUSH32 hBrush = CreateSolidBrush32 (infoPtr->clrBk);
    RECT32 rect;

    GetClientRect32 (wndPtr->hwndSelf, &rect);
    FillRect32 ((HDC32)wParam, &rect, hBrush);
    DeleteObject32 (hBrush);
*/
    return TRUE;
}
#endif



LRESULT WINAPI
ANIMATE_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
{
    WND *wndPtr = WIN_FindWndPtr(hwnd);

    switch (uMsg)
    {
	case ACM_OPEN32A:
	    return ANIMATE_Open32A (wndPtr, wParam, lParam);

//	case ACM_OPEN32W:
//	    return ANIMATE_Open32W (wndPtr, wParam, lParam);

        case ACM_PLAY:
            return ANIMATE_Play (wndPtr, wParam, lParam);

	case ACM_STOP:
	    return ANIMATE_Stop (wndPtr, wParam, lParam);


	case WM_CREATE:
	    return ANIMATE_Create (wndPtr, wParam, lParam);

	case WM_DESTROY:
	    return ANIMATE_Destroy (wndPtr, wParam, lParam);

//	case WM_ERASEBKGND:
//	    return ANIMATE_EraseBackground (wndPtr, wParam, lParam);

//	case WM_NCCREATE:
//	case WM_NCHITTEST:
//	case WM_PAINT:
//	case WM_SIZE:
//	case WM_STYLECHANGED:
//	case WM_TIMER:

	default:
	    if (uMsg >= WM_USER)
		ERR (animate, "unknown msg %04x wp=%08x lp=%08lx\n",
		     uMsg, wParam, lParam);
	    return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
    }
    return 0;
}


VOID
ANIMATE_Register (VOID)
{
    WNDCLASS32A wndClass;

    if (GlobalFindAtom32A (ANIMATE_CLASS32A)) return;

    ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
    wndClass.lpfnWndProc   = (WNDPROC32)ANIMATE_WindowProc;
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(ANIMATE_INFO *);
    wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
    wndClass.hbrBackground = (HBRUSH32)(COLOR_BTNFACE + 1);
    wndClass.lpszClassName = ANIMATE_CLASS32A;
 
    RegisterClass32A (&wndClass);
}


VOID
ANIMATE_Unregister (VOID)
{
    if (GlobalFindAtom32A (ANIMATE_CLASS32A))
	UnregisterClass32A (ANIMATE_CLASS32A, (HINSTANCE32)NULL);
}

wine-981025/dlls/comctl32/comboex.c100644    771    771       14260  6614330267  16667 0ustar  julliardjulliard/*
 * ComboBoxEx control
 *
 * Copyright 1998 Eric Kohl
 *
 * NOTES
 *   This is just a dummy control. An author is needed! Any volunteers?
 *   I will only improve this control once in a while.
 *     Eric <ekohl@abo.rhein-zeitung.de>
 *
 * TODO:
 *   - All messages.
 *   - All notifications.
 *
 * FIXME:
 *   - should include "combo.h" 
 */

#include "windows.h"
#include "commctrl.h"
#include "comboex.h"
#include "win.h"
#include "debug.h"

#define ID_CB_EDIT    1001

#define COMBOEX_GetInfoPtr(wndPtr) ((COMBOEX_INFO *)wndPtr->wExtra[0])


// << COMBOEX_DeleteItem >>


__inline__ static LRESULT
COMBOEX_GetComboControl (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);

    TRACE (comboex, "\n");

    return (LRESULT)infoPtr->hwndCombo;
}


__inline__ static LRESULT
COMBOEX_GetEditControl (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);

    if ((wndPtr->dwStyle & CBS_DROPDOWNLIST) != CBS_DROPDOWN)
	return 0;

    FIXME (comboex, "-- 0x%x\n", GetDlgItem32 (infoPtr->hwndCombo, ID_CB_EDIT));

    return (LRESULT)GetDlgItem32 (infoPtr->hwndCombo, ID_CB_EDIT);
}


__inline__ static LRESULT
COMBOEX_GetExtendedStyle (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);

    return (LRESULT)infoPtr->dwExtStyle;
}


__inline__ static LRESULT
COMBOEX_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);

    TRACE (comboex, "(0x%08x 0x%08lx)\n", wParam, lParam);

    return (LRESULT)infoPtr->himl;
}




static LRESULT
COMBOEX_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);

    FIXME (comboex, "(0x%08x 0x%08lx)\n", wParam, lParam);

    return -1;
}



static LRESULT
COMBOEX_SetExtendedStyle (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);
    DWORD dwTemp;

    TRACE (comboex, "(0x%08x 0x%08lx)\n", wParam, lParam);

    dwTemp = infoPtr->dwExtStyle;

    if ((DWORD)wParam) {
	infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~(DWORD)wParam) | (DWORD)lParam;
    }
    else
	infoPtr->dwExtStyle = (DWORD)lParam;

    /* FIXME: repaint?? */

    return (LRESULT)dwTemp;
}


__inline__ static LRESULT
COMBOEX_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);
    HIMAGELIST himlTemp;

    TRACE (comboex, "(0x%08x 0x%08lx)\n", wParam, lParam);

    himlTemp = infoPtr->himl;
    infoPtr->himl = (HIMAGELIST)lParam;

    return (LRESULT)himlTemp;
}




static LRESULT
COMBOEX_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr;
    DWORD dwComboStyle;

    /* allocate memory for info structure */
    infoPtr = (COMBOEX_INFO *)COMCTL32_Alloc (sizeof(COMBOEX_INFO));
    wndPtr->wExtra[0] = (DWORD)infoPtr;

    if (infoPtr == NULL) {
	ERR (listview, "could not allocate info memory!\n");
	return 0;
    }

    if ((COMBOEX_INFO*)wndPtr->wExtra[0] != infoPtr) {
	ERR (listview, "pointer assignment error!\n");
	return 0;
    }


    /* initialize info structure */


    /* create combo box */
    dwComboStyle = 
	wndPtr->dwStyle & (CBS_SIMPLE|CBS_DROPDOWN|CBS_DROPDOWNLIST|WS_CHILD);

    infoPtr->hwndCombo =
	CreateWindow32A ("ComboBox", "",
			 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | dwComboStyle,
			 0, 0, 0, 0, wndPtr->hwndSelf, (HMENU32)1,
			 wndPtr->hInstance, NULL);


    return 0;
}


static LRESULT
COMBOEX_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);


    if (infoPtr->hwndCombo)
	DestroyWindow32 (infoPtr->hwndCombo);




    /* free comboex info data */
    COMCTL32_Free (infoPtr);

    return 0;
}


static LRESULT
COMBOEX_Size (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr(wndPtr);
    RECT32 rect;

    GetClientRect32 (wndPtr->hwndSelf, &rect);

    MoveWindow32 (infoPtr->hwndCombo, 0, 0, rect.right -rect.left,
		  rect.bottom - rect.top, TRUE);

    return 0;
}


LRESULT WINAPI
COMBOEX_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
{
    WND *wndPtr = WIN_FindWndPtr(hwnd);

    switch (uMsg)
    {
//	case CBEM_DELETEITEM:

	case CBEM_GETCOMBOCONTROL:
	    return COMBOEX_GetComboControl (wndPtr, wParam, lParam);

	case CBEM_GETEDITCONTROL:
	    return COMBOEX_GetEditControl (wndPtr, wParam, lParam);

	case CBEM_GETEXTENDEDSTYLE:
	    return COMBOEX_GetExtendedStyle (wndPtr, wParam, lParam);

	case CBEM_GETIMAGELIST:
	    return COMBOEX_GetImageList (wndPtr, wParam, lParam);

//	case CBEM_GETITEM32A:
//	case CBEM_GETITEM32W:
//	case CBEM_GETUNICODEFORMAT:
//	case CBEM_HASEDITCHANGED:

	case CBEM_INSERTITEM32A:
	    return COMBOEX_InsertItem32A (wndPtr, wParam, lParam);

//	case CBEM_INSERTITEM32W:

	case CBEM_SETEXTENDEDSTYLE:
	    return COMBOEX_SetExtendedStyle (wndPtr, wParam, lParam);

	case CBEM_SETIMAGELIST:
	    return COMBOEX_SetImageList (wndPtr, wParam, lParam);

//	case CBEM_SETITEM32A:
//	case CBEM_SETITEM32W:
//	case CBEM_SETUNICODEFORMAT:


	case WM_CREATE:
	    return COMBOEX_Create (wndPtr, wParam, lParam);

	case WM_DESTROY:
	    return COMBOEX_Destroy (wndPtr, wParam, lParam);

	case WM_SIZE:
	    return COMBOEX_Size (wndPtr, wParam, lParam);

	default:
	    if (uMsg >= WM_USER)
		ERR (comboex, "unknown msg %04x wp=%08x lp=%08lx\n",
		     uMsg, wParam, lParam);
	    return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
    }
    return 0;
}


VOID
COMBOEX_Register (VOID)
{
    WNDCLASS32A wndClass;

    if (GlobalFindAtom32A (WC_COMBOBOXEX32A)) return;

    ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
    wndClass.style         = CS_GLOBALCLASS;
    wndClass.lpfnWndProc   = (WNDPROC32)COMBOEX_WindowProc;
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(COMBOEX_INFO *);
    wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
    wndClass.hbrBackground = (HBRUSH32)(COLOR_WINDOW + 1);
    wndClass.lpszClassName = WC_COMBOBOXEX32A;
 
    RegisterClass32A (&wndClass);
}


VOID
COMBOEX_Unregister (VOID)
{
    if (GlobalFindAtom32A (WC_COMBOBOXEX32A))
	UnregisterClass32A (WC_COMBOBOXEX32A, (HINSTANCE32)NULL);
}

wine-981025/dlls/comctl32/comctl32undoc.c100644    771    771      113130  6614330177  17726 0ustar  julliardjulliard/*
 * Undocumented functions from COMCTL32.DLL
 *
 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
 *           1998 Juergen Schmied <j.schmied@metronet.de>
 * 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).
 *
 * TODO
 *     - Add more functions.
 *     - Write some documentation.
 */

#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "windows.h"
#include "commctrl.h"
#include "heap.h"
#include "debug.h"


extern HANDLE32 COMCTL32_hHeap; /* handle to the private heap */


/**************************************************************************
 * COMCTL32_11 [COMCTL32.11]
 *
 * PARAMS
 *     hdpa1    [I] handle to a dynamic pointer array
 *     hdpa2    [I] handle to a dynamic pointer array
 *     dwParam3
 *     dwParam4
 *     dwParam5
 *     dwParam6
 *
 * NOTES
 *     No more information available yet!
 */

DWORD WINAPI
COMCTL32_11 (HDPA hdpa1, HDPA hdpa2, DWORD dwParam3,
	     DWORD dwParam4, DWORD dwParam5, DWORD dwParam6)
{

    FIXME (commctrl, "(%p %p %08lx %08lx %08lx %08lx): empty stub\n",
	   hdpa1, hdpa2, dwParam3, dwParam4, dwParam5, dwParam6);

    return 0;
}


/**************************************************************************
 * Alloc [COMCTL32.71]
 *
 * Allocates memory block from the dll's private heap
 *
 * PARAMS
 *     dwSize [I] size of the allocated memory block
 *
 * RETURNS
 *     Success: pointer to allocated memory block
 *     Failure: NULL
 */

LPVOID WINAPI
COMCTL32_Alloc (DWORD dwSize)
{
    LPVOID lpPtr;

    TRACE (commctrl, "(0x%lx)\n", dwSize);

    lpPtr = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);

    TRACE (commctrl, "-- ret=%p\n", lpPtr);

    return lpPtr;
}


/**************************************************************************
 * ReAlloc [COMCTL32.72]
 *
 * Changes the size of an allocated memory block or allocates a memory
 * block using the dll's private heap.
 *
 * 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
 *     If lpSrc is a NULL-pointer, then COMCTL32_ReAlloc allocates a memory
 *     block like COMCTL32_Alloc.
 */

LPVOID WINAPI
COMCTL32_ReAlloc (LPVOID lpSrc, DWORD dwSize)
{
    LPVOID lpDest;

    TRACE (commctrl, "(%p 0x%08lx)\n", lpSrc, dwSize);

    if (lpSrc)
	lpDest = HeapReAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, lpSrc, dwSize);
    else
	lpDest = HeapAlloc (COMCTL32_hHeap, HEAP_ZERO_MEMORY, dwSize);

    TRACE (commctrl, "-- ret=%p\n", lpDest);

    return lpDest;
}


/**************************************************************************
 * Free [COMCTL32.73]
.*
 * Frees an allocated memory block from the dll's private heap.
 *
 * PARAMS
 *     lpMem [I] pointer to memory block which will be freed
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
COMCTL32_Free (LPVOID lpMem)
{
    TRACE (commctrl, "(%p)\n", lpMem);

    return HeapFree (COMCTL32_hHeap, 0, lpMem);
}


/**************************************************************************
 * GetSize [COMCTL32.74]
 *
 * Retrieves the size of the specified memory block from the dll's
 * private heap.
 *
 * PARAMS
 *     lpMem [I] pointer to an allocated memory block
 *
 * RETURNS
 *     Success: size of the specified memory block
 *     Failure: 0
 */

DWORD WINAPI
COMCTL32_GetSize (LPVOID lpMem)
{
    TRACE (commctrl, "(%p)\n", lpMem);

    return HeapSize (COMCTL32_hHeap, 0, lpMem);
}


/**************************************************************************
 * The MRU-API is a set of functions to manipulate MRU(Most Recently Used)
 * lists.
 *
 *
 */

typedef struct tagMRUINFO
{
    DWORD  dwParam1;
    DWORD  dwParam2;
    DWORD  dwParam3;
    HKEY   hkeyMain;
    LPCSTR lpszSubKey;
    DWORD  dwParam6;
} MRUINFO, *LPMRUINFO;

 
typedef struct tagMRU
{
    DWORD  dwParam1;  /* some kind of flag */
    DWORD  dwParam2;
    DWORD  dwParam3;
    HKEY   hkeyMRU;
    LPCSTR lpszSubKey;
    DWORD  dwParam6;
} MRU, *HMRU;

LPVOID WINAPI
CreateMRUListEx32A (LPMRUINFO lpmi, DWORD dwParam2,
		    DWORD dwParam3, DWORD dwParam4);


/**************************************************************************
 * CreateMRUListA [COMCTL32.151]
 *
 * PARAMS
 *     dwParam
 *
 * RETURNS
 */

LPVOID WINAPI
CreateMRUList32A (LPMRUINFO lpmi)
{
     return CreateMRUListEx32A (lpmi, 0, 0, 0);
}


DWORD WINAPI
FreeMRUList32A (HMRU hmru)
{
    FIXME (commctrl, "(%p) empty stub!\n", hmru);

#if 0
    if (!(hmru->dwParam1 & 1001)) {
	RegSetValueEx32A (hmru->hKeyMRU, "MRUList", 0, REG_SZ,
			  hmru->lpszMRUString,
			  lstrlen32A (hmru->lpszMRUString));
    }


    RegClosKey32 (hmru->hkeyMRU
    COMCTL32_Free32 (hmru->lpszMRUString);
#endif

    return COMCTL32_Free (hmru);
}



DWORD WINAPI
AddMRUData (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{

    FIXME (commctrl, "(%lx %lx %lx) empty stub!\n",
	   dwParam1, dwParam2, dwParam3);

    return 0;
}


DWORD WINAPI
FindMRUData (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
{

    FIXME (commctrl, "(%lx %lx %lx %lx) empty stub!\n",
	   dwParam1, dwParam2, dwParam3, dwParam4);

    return TRUE;
}


LPVOID WINAPI
CreateMRUListEx32A (LPMRUINFO lpmi, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
{
    DWORD  dwLocal1;
    HKEY   hkeyResult;
    DWORD  dwLocal3;
    LPVOID lMRU;
    DWORD  dwLocal5;
    DWORD  dwLocal6;
    DWORD  dwLocal7;
    DWORD  dwDisposition;

    /* internal variables */
    LPVOID ptr;

    FIXME (commctrl, "(%p) empty stub!\n", lpmi);

    if (lpmi) {
	FIXME (commctrl, "(%lx %lx %lx %lx \"%s\" %lx)\n",
	       lpmi->dwParam1, lpmi->dwParam2, lpmi->dwParam3,
	       lpmi->hkeyMain, lpmi->lpszSubKey, lpmi->dwParam6);
    }

    /* dummy pointer creation */
    ptr = COMCTL32_Alloc (32);

    FIXME (commctrl, "-- ret = %p\n", ptr);

    return ptr;
}




/**************************************************************************
 * Str_GetPtrA [COMCTL32.233]
 *
 * PARAMS
 *     lpSrc   [I]
 *     lpDest  [O]
 *     nMaxLen [I]
 *
 * RETURNS
 */

INT32 WINAPI
Str_GetPtr32A (LPCSTR lpSrc, LPSTR lpDest, INT32 nMaxLen)
{
    INT32 len;

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

    if (!lpDest && lpSrc)
	return lstrlen32A (lpSrc);

    if (nMaxLen == 0)
	return 0;

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

    len = lstrlen32A (lpSrc);
    if (len >= nMaxLen)
	len = nMaxLen - 1;

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

    return len;
}


/**************************************************************************
 * Str_SetPtrA [COMCTL32.234]
 *
 * PARAMS
 *     lppDest [O]
 *     lpSrc   [I]
 *
 * RETURNS
 */

BOOL32 WINAPI
Str_SetPtr32A (LPSTR *lppDest, LPCSTR lpSrc)
{
    TRACE (commctrl, "(%p %p)\n", lppDest, lpSrc);
 
    if (lpSrc) {
	LPSTR ptr = COMCTL32_ReAlloc (lppDest, lstrlen32A (lpSrc) + 1);
	if (!ptr)
	    return FALSE;
	lstrcpy32A (ptr, lpSrc);
	*lppDest = ptr;
    }
    else {
	if (*lppDest) {
	    COMCTL32_Free (*lppDest);
	    *lppDest = NULL;
	}
    }

    return TRUE;
}


/**************************************************************************
 * Str_GetPtrW [COMCTL32.235]
 *
 * PARAMS
 *     lpSrc   [I]
 *     lpDest  [O]
 *     nMaxLen [I]
 *
 * RETURNS
 */

INT32 WINAPI
Str_GetPtr32W (LPCWSTR lpSrc, LPWSTR lpDest, INT32 nMaxLen)
{
    INT32 len;

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

    if (!lpDest && lpSrc)
	return lstrlen32W (lpSrc);

    if (nMaxLen == 0)
	return 0;

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

    len = lstrlen32W (lpSrc);
    if (len >= nMaxLen)
	len = nMaxLen - 1;

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

    return len;
}


/**************************************************************************
 * Str_SetPtrW [COMCTL32.236]
 *
 * PARAMS
 *     lpDest [O]
 *     lpSrc  [I]
 *
 * RETURNS
 */

BOOL32 WINAPI
Str_SetPtr32W (LPWSTR *lppDest, LPCWSTR lpSrc)
{
    TRACE (commctrl, "(%p %p)\n", lppDest, lpSrc);
 
    if (lpSrc) {
	INT32 len = lstrlen32W (lpSrc) + 1;
	LPWSTR ptr = COMCTL32_ReAlloc (lppDest, len * sizeof(WCHAR));
	if (!ptr)
	    return FALSE;
	lstrcpy32W (ptr, lpSrc);
	*lppDest = ptr;
    }
    else {
	if (*lppDest) {
	    COMCTL32_Free (*lppDest);
	    *lppDest = NULL;
	}
    }

    return TRUE;
}


/**************************************************************************
 * The DSA-API is a set of functions to create and manipulate arrays of
 * fix sized memory blocks. These arrays can store any kind of data
 * (strings, icons...).
 */

/**************************************************************************
 * DSA_Create [COMCTL32.320] Creates a dynamic storage array
 *
 * PARAMS
 *     nSize [I] size of the array elements
 *     nGrow [I] number of elements by which the array grows when it is filled
 *
 * RETURNS
 *     Success: pointer to a array control structure. use this like a handle.
 *     Failure: NULL
 */

HDSA WINAPI
DSA_Create (INT32 nSize, INT32 nGrow)
{
    HDSA hdsa;

    TRACE (commctrl, "(size=%d grow=%d)\n", nSize, nGrow);

    hdsa = (HDSA)COMCTL32_Alloc (sizeof(DSA));
    if (hdsa)
    {
	hdsa->nItemCount = 0;
        hdsa->pData = NULL;
	hdsa->nMaxCount = 0;
	hdsa->nItemSize = nSize;
	hdsa->nGrow = MAX(1, nGrow);
    }

    return hdsa;
}


/**************************************************************************
 * DSA_Destroy [COMCTL32.321] Destroys a dynamic storage array
 *
 * PARAMS
 *     hdsa [I] pointer to the array control structure
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DSA_Destroy (const HDSA hdsa)
{
    TRACE (commctrl, "(%p)\n", hdsa);

    if (!hdsa)
	return FALSE;

    if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
	return FALSE;

    return COMCTL32_Free (hdsa);
}


/**************************************************************************
 * DSA_GetItem [COMCTL32.322] 
 *
 * PARAMS
 *     hdsa   [I] pointer to the array control structure
 *     nIndex [I] number of the Item to get
 *     pDest  [O] destination buffer. Has to be >= dwElementSize.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DSA_GetItem (const HDSA hdsa, INT32 nIndex, LPVOID pDest)
{
    LPVOID pSrc;

    TRACE (commctrl, "(%p %d %p)\n", hdsa, nIndex, pDest);
    
    if (!hdsa)
	return FALSE;
    if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
	return FALSE;

    pSrc = hdsa->pData + (hdsa->nItemSize * nIndex);
    memmove (pDest, pSrc, hdsa->nItemSize);

    return TRUE;
}


/**************************************************************************
 * DSA_GetItemPtr [COMCTL32.323] 
 *
 * Retrieves a pointer to the specified item.
 *
 * PARAMS
 *     hdsa   [I] pointer to the array control structure
 *     nIndex [I] index of the desired item
 *
 * RETURNS
 *     Success: pointer to an item
 *     Failure: NULL
 */

LPVOID WINAPI
DSA_GetItemPtr (const HDSA hdsa, INT32 nIndex)
{
    LPVOID pSrc;

    TRACE (commctrl, "(%p %d)\n", hdsa, nIndex);

    if (!hdsa)
	return NULL;
    if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
	return NULL;

    pSrc = hdsa->pData + (hdsa->nItemSize * nIndex);
    
    TRACE (commctrl, "-- ret=%p\n", pSrc);

    return  pSrc;
}


/**************************************************************************
 * DSA_SetItem [COMCTL32.325] 
 *
 * Sets the contents of an item in the array.
 *
 * PARAMS
 *     hdsa   [I] pointer to the array control structure
 *     nIndex [I] index for the item
 *     pSrc   [I] pointer to the new item data
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DSA_SetItem (const HDSA hdsa, INT32 nIndex, LPVOID pSrc)
{
    INT32  nSize, nNewItems;
    LPVOID pDest, lpTemp;
    
    TRACE (commctrl, "(%p %d %p)\n", hdsa, nIndex, pSrc);

    if ((!hdsa) || nIndex < 0)
	return FALSE;
      
    if (hdsa->nItemCount <= nIndex) {
	/* within the old array */
	if (hdsa->nMaxCount > nIndex) {
	    /* within the allocated space, set a new boundary */
	    hdsa->nItemCount = nIndex;
	}
	else {
	    /* resize the block of memory */
	    nNewItems =
		hdsa->nGrow * ((INT32)((nIndex - 1) / hdsa->nGrow) + 1);
	    nSize = hdsa->nItemSize * nNewItems;

	    lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
	    if (!lpTemp)
		return FALSE;

	    hdsa->nMaxCount = nNewItems;
	    hdsa->pData = lpTemp;
	}    
    }

    /* put the new entry in */
    pDest = hdsa->pData + (hdsa->nItemSize * nIndex);
    TRACE (commctrl, "-- move dest=%p src=%p size=%d\n",
	   pDest, pSrc, hdsa->nItemSize);
    memmove (pDest, pSrc, hdsa->nItemSize);

    return TRUE;
}


/**************************************************************************
 * DSA_InsertItem [COMCTL32.325] 
 *
 * PARAMS
 *     hdsa   [I] pointer to the array control structure
 *     nIndex [I] index for the new item
 *     pSrc   [I] pointer to the element
 *
 * RETURNS
 *     Success: position of the new item
 *     Failure: -1
 */

INT32 WINAPI
DSA_InsertItem (const HDSA hdsa, INT32 nIndex, LPVOID pSrc)
{
    INT32   nNewItems, nSize, i;
    LPVOID  lpTemp, lpDest;
    LPDWORD p;
    
    TRACE(commctrl, "(%p %d %p)\n", hdsa, nIndex, pSrc);

    if ((!hdsa) || nIndex < 0)
	return -1;

    for (i = 0; i < hdsa->nItemSize; i += 4) {
	p = *(DWORD**)(pSrc + i);
	if (IsBadStringPtr32A ((char*)p, 256))
	    TRACE (commctrl, "-- %d=%p\n", i, (DWORD*)p);
	else
	    TRACE (commctrl, "-- %d=%p [%s]\n", i, p, debugstr_a((char*)p));
    }
   
    /* when nIndex > nItemCount then append */
    if (nIndex >= hdsa->nItemCount)
 	nIndex = hdsa->nItemCount;

    /* do we need to resize ? */
    if (hdsa->nItemCount >= hdsa->nMaxCount) {
	nNewItems = hdsa->nMaxCount + hdsa->nGrow;
	nSize = hdsa->nItemSize * nNewItems;

	lpTemp = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
	if (!lpTemp)
	    return -1;

	hdsa->nMaxCount = nNewItems;
	hdsa->pData = lpTemp;         
    }

    /* do we need to move elements ? */
    if (nIndex < hdsa->nItemCount) {
	lpTemp = hdsa->pData + (hdsa->nItemSize * nIndex);
	lpDest = lpTemp + hdsa->nItemSize;
	nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
	TRACE (commctrl, "-- move dest=%p src=%p size=%d\n",
	       lpDest, lpTemp, nSize);
	memmove (lpDest, lpTemp, nSize);
    }

    /* ok, we can put the new Item in */
    hdsa->nItemCount++;
    lpDest = hdsa->pData + (hdsa->nItemSize * nIndex);
    TRACE (commctrl, "-- move dest=%p src=%p size=%d\n",
	   lpDest, pSrc, hdsa->nItemSize);
    memmove (lpDest, pSrc, hdsa->nItemSize);

    return hdsa->nItemCount;
}


/**************************************************************************
 * DSA_DeleteItem [COMCTL32.326] 
 *
 * PARAMS
 *     hdsa   [I] pointer to the array control structure
 *     nIndex [I] index for the element to delete
 *
 * RETURNS
 *     Success: number of the deleted element
 *     Failure: -1
 */

INT32 WINAPI
DSA_DeleteItem (const HDSA hdsa, INT32 nIndex)
{
    LPVOID lpDest,lpSrc;
    INT32  nSize;
    
    TRACE (commctrl, "(%p %d)\n", hdsa, nIndex);

    if (!hdsa)
	return -1;
    if (nIndex < 0 || nIndex >= hdsa->nItemCount)
	return -1;

    /* do we need to move ? */
    if (nIndex < hdsa->nItemCount - 1) {
	lpDest = hdsa->pData + (hdsa->nItemSize * nIndex);
	lpSrc = lpDest + hdsa->nItemSize;
	nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
	TRACE (commctrl, "-- move dest=%p src=%p size=%d\n",
	       lpDest, lpSrc, nSize);
	memmove (lpDest, lpSrc, nSize);
    }
    
    hdsa->nItemCount--;
    
    /* free memory ? */
    if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
	nSize = hdsa->nItemSize * hdsa->nItemCount;

	lpDest = (LPVOID)COMCTL32_ReAlloc (hdsa->pData, nSize);
	if (!lpDest)
	    return -1;

	hdsa->nMaxCount = hdsa->nItemCount;
	hdsa->pData = lpDest;
    }

    return nIndex;
}


/**************************************************************************
 * DSA_DeleteAllItems [COMCTL32.326]
 *
 * Removes all items and reinitializes the array.
 *
 * PARAMS
 *     hdsa [I] pointer to the array control structure
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DSA_DeleteAllItems (const HDSA hdsa)
{
    TRACE (commctrl, "(%p)\n", hdsa);

    if (!hdsa) 
	return FALSE;
    if (hdsa->pData && (!COMCTL32_Free (hdsa->pData)))
	return FALSE;

    hdsa->nItemCount = 0;
    hdsa->pData = NULL;
    hdsa->nMaxCount = 0;

    return TRUE;
}


/**************************************************************************
 * The DPA-API is a set of functions to create and manipulate arrays of
 * pointers.
 */

/**************************************************************************
 * DPA_Create [COMCTL32.328] Creates a dynamic pointer array
 *
 * PARAMS
 *     nGrow [I] number of items by which the array grows when it is filled
 *
 * RETURNS
 *     Success: handle (pointer) to the pointer array.
 *     Failure: NULL
 */

HDPA WINAPI
DPA_Create (INT32 nGrow)
{
    HDPA hdpa;

    TRACE (commctrl, "(%d)\n", nGrow);

    hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));
    if (hdpa) {
	hdpa->nGrow = MAX(8, nGrow);
	hdpa->hHeap = COMCTL32_hHeap;
	hdpa->nMaxCount = hdpa->nGrow * 2;
	hdpa->ptrs =
	    (LPVOID*)COMCTL32_Alloc (hdpa->nMaxCount * sizeof(LPVOID));
    }

    TRACE (commctrl, "-- %p\n", hdpa);

    return hdpa;
}


/**************************************************************************
 * DPA_Destroy [COMCTL32.329] Destroys a dynamic pointer array
 *
 * PARAMS
 *     hdpa [I] handle (pointer) to the pointer array
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DPA_Destroy (const HDPA hdpa)
{
    TRACE (commctrl, "(%p)\n", hdpa);

    if (!hdpa)
	return FALSE;

    if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
	return FALSE;

    return HeapFree (hdpa->hHeap, 0, hdpa);
}


/**************************************************************************
 * DPA_Grow [COMCTL32.330]
 *
 * Sets the growth amount.
 *
 * PARAMS
 *     hdpa  [I] handle (pointer) to the existing (source) pointer array
 *     nGrow [I] number of items, the array grows, when it's too small
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DPA_Grow (const HDPA hdpa, INT32 nGrow)
{
    TRACE (commctrl, "(%p %d)\n", hdpa, nGrow);

    if (!hdpa)
	return FALSE;

    hdpa->nGrow = MAX(8, nGrow);

    return TRUE;
}


/**************************************************************************
 * DPA_Clone [COMCTL32.331]
 *
 * Copies a pointer array to an other one or creates a copy
 *
 * PARAMS
 *     hdpa    [I] handle (pointer) to the existing (source) pointer array
 *     hdpaNew [O] handle (pointer) to the destination pointer array
 *
 * RETURNS
 *     Success: pointer to the destination pointer array.
 *     Failure: NULL
 *
 * NOTES
 *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
 *       array will be created and it's handle (pointer) is returned.
 *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
 *       this implementation just returns NULL.
 */

HDPA WINAPI
DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
{
    INT32 nNewItems, nSize;
    HDPA hdpaTemp;

    if (!hdpa)
	return NULL;

    TRACE (commctrl, "(%p %p)\n", hdpa, hdpaNew);

    if (!hdpaNew) {
	/* create a new DPA */
	hdpaTemp = (HDPA)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
				    sizeof(DPA));
	hdpaTemp->hHeap = hdpa->hHeap;
	hdpaTemp->nGrow = hdpa->nGrow;
    }
    else
	hdpaTemp = hdpaNew;

    if (hdpaTemp->ptrs) {
	/* remove old pointer array */
	HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
	hdpaTemp->ptrs = NULL;
	hdpaTemp->nItemCount = 0;
	hdpaTemp->nMaxCount = 0;
    }

    /* create a new pointer array */
    nNewItems = hdpaTemp->nGrow *
		((INT32)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
    nSize = nNewItems * sizeof(LPVOID);
    hdpaTemp->ptrs =
	(LPVOID*)HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
    hdpaTemp->nMaxCount = nNewItems;

    /* clone the pointer array */
    hdpaTemp->nItemCount = hdpa->nItemCount;
    memmove (hdpaTemp->ptrs, hdpa->ptrs,
	     hdpaTemp->nItemCount * sizeof(LPVOID));

    return hdpaTemp;
}


/**************************************************************************
 * DPA_GetPtr [COMCTL32.332]
 *
 * Retrieves a pointer from a dynamic pointer array
 *
 * PARAMS
 *     hdpa   [I] handle (pointer) to the pointer array
 *     nIndex [I] array index of the desired pointer
 *
 * RETURNS
 *     Success: pointer
 *     Failure: NULL
 */

LPVOID WINAPI
DPA_GetPtr (const HDPA hdpa, INT32 i)
{
    TRACE (commctrl, "(%p %d)\n", hdpa, i);

    if (!hdpa)
	return NULL;
    if (!hdpa->ptrs)
	return NULL;
    if ((i < 0) || (i >= hdpa->nItemCount))
	return NULL;

    TRACE (commctrl, "-- %p\n", hdpa->ptrs[i]);

    return hdpa->ptrs[i];
}


/**************************************************************************
 * DPA_GetPtrIndex [COMCTL32.333]
 *
 * Retrieves the index of the specified pointer
 *
 * PARAMS
 *     hdpa   [I] handle (pointer) to the pointer array
 *     p      [I] pointer
 *
 * RETURNS
 *     Success: index of the specified pointer
 *     Failure: -1
 */

INT32 WINAPI
DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
{
    INT32 i;

    if (!hdpa->ptrs)
	return -1;

    for (i = 0; i < hdpa->nItemCount; i++) {
	if (hdpa->ptrs[i] == p)
	    return i;
    }

    return -1;
}


/**************************************************************************
 * DPA_InsertPtr [COMCTL32.334]
 *
 * Inserts a pointer into a dynamic pointer array
 *
 * PARAMS
 *     hdpa [I] handle (pointer) to the array
 *     i    [I] array index
 *     p    [I] pointer to insert
 *
 * RETURNS
 *     Success: index of the inserted pointer
 *     Failure: -1
 */

INT32 WINAPI
DPA_InsertPtr (const HDPA hdpa, INT32 i, LPVOID p)
{
    INT32   nNewItems, nSize, nIndex = 0;
    LPVOID  *lpTemp, *lpDest;

    TRACE (commctrl, "(%p %d %p)\n", hdpa, i, p);

    if ((!hdpa) || (i < 0))
	return -1;

    if (!hdpa->ptrs) {
	hdpa->ptrs =
	    (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
				2 * hdpa->nGrow * sizeof(LPVOID));
	if (!hdpa->ptrs)
	    return -1;
	hdpa->nMaxCount = hdpa->nGrow * 2;
        nIndex = 0;
    }
    else {
	if (hdpa->nItemCount >= hdpa->nMaxCount) {
	    TRACE (commctrl, "-- resizing\n");
	    nNewItems = hdpa->nMaxCount + hdpa->nGrow;
	    nSize = nNewItems * sizeof(LPVOID);

	    lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
					   hdpa->ptrs, nSize);
	    if (!lpTemp)
		return -1;
	    hdpa->nMaxCount = nNewItems;
	    hdpa->ptrs = lpTemp;
	}

	if (i >= hdpa->nItemCount) {
	    nIndex = hdpa->nItemCount;
	    TRACE (commctrl, "-- appending at %d\n", nIndex);
	}
	else {
	    TRACE (commctrl, "-- inserting at %d\n", i);
	    lpTemp = hdpa->ptrs + (sizeof(LPVOID) * i);
	    lpDest = lpTemp + sizeof(LPVOID);
	    nSize  = (hdpa->nItemCount - i) * sizeof(LPVOID);
	    TRACE (commctrl, "-- move dest=%p src=%p size=%x\n",
		   lpDest, lpTemp, nSize);
	    memmove (lpDest, lpTemp, nSize);
	    nIndex = i;
	}
    }

    /* insert item */
    hdpa->nItemCount++;
    hdpa->ptrs[nIndex] = p;

    return nIndex;
}


/**************************************************************************
 * DPA_SetPtr [COMCTL32.335]
 *
 * Sets a pointer in the pointer array
 *
 * PARAMS
 *     hdpa [I] handle (pointer) to the pointer array
 *     i    [I] index of the pointer that will be set
 *     p    [I] pointer to be set
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DPA_SetPtr (const HDPA hdpa, INT32 i, LPVOID p)
{
    LPVOID *lpTemp;
    
    TRACE (commctrl, "(%p %d %p)\n", hdpa, i, p);

    if ((!hdpa) || i < 0)
	return FALSE;
      
    if (hdpa->nItemCount <= i) {
	/* within the old array */
	if (hdpa->nMaxCount > i) {
	    /* within the allocated space, set a new boundary */
	    hdpa->nItemCount = i;
	}
	else {
	    /* resize the block of memory */
	    INT32 nNewItems =
		hdpa->nGrow * ((INT32)((i - 1) / hdpa->nGrow) + 1);
	    INT32 nSize = nNewItems * sizeof(LPVOID);

	    lpTemp = (LPVOID*)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
					   hdpa->ptrs, nSize);
	    if (!lpTemp)
		return FALSE;

	    hdpa->nItemCount = nNewItems;
	    hdpa->ptrs = lpTemp;        
	}    
    }

    /* put the new entry in */
    hdpa->ptrs[i] = p;

    return TRUE;
}


/**************************************************************************
 * DPA_DeletePtr [COMCTL32.336]
 *
 * Removes a pointer from the pointer array.
 *
 * PARAMS
 *     hdpa [I] handle (pointer) to the pointer array
 *     i    [I] index of the pointer that will be deleted
 *
 * RETURNS
 *     Success: deleted pointer
 *     Failure: NULL
 */

LPVOID WINAPI
DPA_DeletePtr (const HDPA hdpa, INT32 i)
{
    LPVOID lpDest, lpSrc, lpTemp = NULL;
    INT32  nSize;
    
    TRACE (commctrl, "(%p %d)\n", hdpa, i);

    if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
	return NULL;

    lpTemp = hdpa->ptrs[i];

    /* do we need to move ?*/
    if (i < hdpa->nItemCount - 1) {
	lpDest = hdpa->ptrs + (i * sizeof (LPVOID));
	lpSrc = lpDest + sizeof(LPVOID);
	nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
	TRACE (commctrl,"-- move dest=%p src=%p size=%x\n",
	       lpDest, lpSrc, nSize);
	memmove (lpDest, lpSrc, nSize);
    }
    
    hdpa->nItemCount --;
    
    /* free memory ?*/
    if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
	INT32 nNewItems = MIN(hdpa->nGrow * 2, hdpa->nItemCount);
	nSize = nNewItems * sizeof(LPVOID);
	lpDest = (LPVOID)HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
				      hdpa->ptrs, nSize);
	if (!lpDest)
	    return NULL;

	hdpa->nMaxCount = nNewItems;
	hdpa->ptrs = (LPVOID*)lpDest;         
    }

    return lpTemp;
}


/**************************************************************************
 * DPA_DeleteAllPtrs [COMCTL32.337]
 *
 * Removes all pointers and reinitializes the array.
 *
 * PARAMS
 *     hdpa [I] handle (pointer) to the pointer array
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DPA_DeleteAllPtrs (const HDPA hdpa)
{
    TRACE (commctrl, "(%p)\n", hdpa);

    if (!hdpa) 
	return FALSE;

    if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
	return FALSE;

    hdpa->nItemCount = 0;
    hdpa->nMaxCount = hdpa->nGrow * 2;
    hdpa->ptrs = (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
				     hdpa->nMaxCount * sizeof(LPVOID));

    return TRUE;
}


/**************************************************************************
 * DPA_QuickSort [Internal]
 *
 * Ordinary quicksort (used by DPA_Sort).
 *
 * PARAMS
 *     lpPtrs     [I] pointer to the pointer array
 *     l          [I] index of the "left border" of the partition
 *     r          [I] index of the "right border" of the partition
 *     pfnCompare [I] pointer to the compare function
 *     lParam     [I] user defined value (3rd parameter in compare function)
 *
 * RETURNS
 *     NONE
 */

static VOID
DPA_QuickSort (LPVOID *lpPtrs, INT32 l, INT32 r,
	       PFNDPACOMPARE pfnCompare, LPARAM lParam)
{
    LPVOID t, v;
    INT32  i, j;

    TRACE (commctrl, "l=%i r=%i\n", l, r);
 
    i = l;
    j = r;
    v = lpPtrs[(int)(l+r)/2];
    do {
	while ((pfnCompare)(lpPtrs[i], v, lParam) < 0) i++;
	while ((pfnCompare)(lpPtrs[j], v, lParam) > 0) j--;
	if (i <= j) 
	{
	    t = lpPtrs[i];
	    lpPtrs[i++] = lpPtrs[j];
	    lpPtrs[j--] = t;
	}
    } while (i <= j);
    if (l < j) DPA_QuickSort (lpPtrs, l, j, pfnCompare, lParam);
    if (i < r) DPA_QuickSort (lpPtrs, i, r, pfnCompare, lParam);
}


/**************************************************************************
 * DPA_Sort [COMCTL32.338]
 *
 * Sorts a pointer array using a user defined compare function
 *
 * PARAMS
 *     hdpa       [I] handle (pointer) to the pointer array
 *     pfnCompare [I] pointer to the compare function
 *     lParam     [I] user defined value (3rd parameter of compare function)
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
{
    if (!hdpa || !pfnCompare)
	return FALSE;

    TRACE (commctrl, "(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);

    if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
	DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
		       pfnCompare, lParam);

    return TRUE;
}


/**************************************************************************
 * DPA_Search [COMCTL32.339]
 *
 * Searches a pointer array for a specified pointer
 *
 * PARAMS
 *     hdpa       [I] handle (pointer) to the pointer array
 *     pFind      [I] pointer to search for
 *     nStart     [I] start index
 *     pfnCompare [I] pointer to the compare function
 *     lParam     [I] user defined value (3rd parameter of compare function)
 *     uOptions   [I] search options
 *
 * RETURNS
 *     Success: index of the pointer in the array.
 *     Failure: -1
 *
 * NOTES
 *     Binary search taken from R.Sedgewick "Algorithms in C"!
 *     Function is NOT tested!
 *     If something goes wrong, blame HIM not ME! (Eric Kohl)
 */

INT32 WINAPI
DPA_Search (const HDPA hdpa, LPVOID pFind, INT32 nStart,
	    PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT32 uOptions)
{
    if (!hdpa || !pfnCompare || !pFind)
	return -1;

    TRACE (commctrl, "(%p %p %d %p 0x%08lx 0x%08x)\n",
	   hdpa, pFind, nStart, pfnCompare, lParam, uOptions);

    if (uOptions & DPAS_SORTED) {
	/* array is sorted --> use binary search */
	INT32 l, r, x, n;
	LPVOID *lpPtr;

	TRACE (commctrl, "binary search\n");

	l = (nStart == -1) ? 0 : nStart;
	r = hdpa->nItemCount - 1;
	lpPtr = hdpa->ptrs;
	while (r >= l) {
	    x = (l + r) / 2;
	    n = (pfnCompare)(pFind, lpPtr[x], lParam);
	    if (n < 0)
		r = x - 1;
	    else
		l = x + 1;
	    if (n == 0) {
		TRACE (commctrl, "-- ret=%d\n", n);
		return n;
	    }
	}

	if (uOptions & DPAS_INSERTBEFORE) {
	    TRACE (commctrl, "-- ret=%d\n", r);
	    return r;
	}

	if (uOptions & DPAS_INSERTAFTER) {
	    TRACE (commctrl, "-- ret=%d\n", l);
	    return l;
	}
    }
    else {
	/* array is not sorted --> use linear search */
	LPVOID *lpPtr;
	INT32  nIndex;

	TRACE (commctrl, "linear search\n");
	
	nIndex = (nStart == -1)? 0 : nStart;
	lpPtr = hdpa->ptrs;
	for (; nIndex < hdpa->nItemCount; nIndex++) {
	    if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
		TRACE (commctrl, "-- ret=%d\n", nIndex);
		return nIndex;
	    }
	}
    }

    TRACE (commctrl, "-- not found: ret=-1\n");
    return -1;
}


/**************************************************************************
 * DPA_CreateEx [COMCTL32.340]
 *
 * Creates a dynamic pointer array using the specified size and heap.
 *
 * PARAMS
 *     nGrow [I] number of items by which the array grows when it is filled
 *     hHeap [I] handle to the heap where the array is stored
 *
 * RETURNS
 *     Success: handle (pointer) to the pointer array.
 *     Failure: NULL
 */

HDPA WINAPI
DPA_CreateEx (INT32 nGrow, HANDLE32 hHeap)
{
    HDPA hdpa;

    TRACE (commctrl, "(%d 0x%x)\n", nGrow, hHeap);

    if (hHeap)
	hdpa = (HDPA)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(DPA));
    else
	hdpa = (HDPA)COMCTL32_Alloc (sizeof(DPA));

    if (hdpa) {
	hdpa->nGrow = MIN(8, nGrow);
	hdpa->hHeap = hHeap ? hHeap : COMCTL32_hHeap;
	hdpa->nMaxCount = hdpa->nGrow * 2;
	hdpa->ptrs =
	    (LPVOID*)HeapAlloc (hHeap, HEAP_ZERO_MEMORY,
				hdpa->nMaxCount * sizeof(LPVOID));
    }

    TRACE (commctrl, "-- %p\n", hdpa);

    return hdpa;
}


/**************************************************************************
 * Notification functions
 */

typedef struct tagNOTIFYDATA
{
    HWND32 hwndFrom;
    HWND32 hwndTo;
    DWORD  dwParam3;
    DWORD  dwParam4;
    DWORD  dwParam5;
    DWORD  dwParam6;
} NOTIFYDATA, *LPNOTIFYDATA;


/**************************************************************************
 * DoNotify [Internal]
 */

static LRESULT
DoNotify (LPNOTIFYDATA lpNotify, UINT32 uCode, LPNMHDR lpHdr)
{
    NMHDR nmhdr;
    LPNMHDR lpNmh = NULL;
    UINT32 idFrom = 0;

    TRACE (commctrl, "(0x%04x 0x%04x %d %p 0x%08lx)\n",
	   lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
	   lpNotify->dwParam5);

    if (!lpNotify->hwndTo)
	return 0;

    if (lpNotify->hwndFrom == -1) {
	lpNmh = lpHdr;
	idFrom = lpHdr->idFrom;
    }
    else {
	if (lpNotify->hwndFrom) {
	    HWND32 hwndParent = GetParent32 (lpNotify->hwndFrom);
	    if (hwndParent) {
		hwndParent = GetWindow32 (lpNotify->hwndFrom, GW_OWNER);
		if (hwndParent)
		    idFrom = GetDlgCtrlID32 (lpNotify->hwndFrom);
	    }
	}

	lpNmh = (lpHdr) ? lpHdr : &nmhdr;

	lpNmh->hwndFrom = lpNotify->hwndFrom;
	lpNmh->idFrom = idFrom;
	lpNmh->code = uCode;
    }

    return SendMessage32A (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
}


/**************************************************************************
 * SendNotify [COMCTL32.341]
 *
 * PARAMS
 *     hwndFrom [I]
 *     hwndTo   [I]
 *     uCode    [I]
 *     lpHdr    [I]
 *
 * RETURNS
 *     Success: return value from notification
 *     Failure: 0
 */

LRESULT WINAPI
COMCTL32_SendNotify (HWND32 hwndFrom, HWND32 hwndTo,
		     UINT32 uCode, LPNMHDR lpHdr)
{
    NOTIFYDATA notify;

    TRACE (commctrl, "(0x%04x 0x%04x %d %p)\n",
	   hwndFrom, hwndTo, uCode, lpHdr);

    notify.hwndFrom = hwndFrom;
    notify.hwndTo   = hwndTo;
    notify.dwParam5 = 0;
    notify.dwParam6 = 0;

    return DoNotify (&notify, uCode, lpHdr);
}


/**************************************************************************
 * SendNotifyEx [COMCTL32.342]
 *
 * PARAMS
 *     hwndFrom [I]
 *     hwndTo   [I]
 *     uCode    [I]
 *     lpHdr    [I]
 *     dwParam5 [I]
 *
 * RETURNS
 *     Success: return value from notification
 *     Failure: 0
 */

LRESULT WINAPI
COMCTL32_SendNotifyEx (HWND32 hwndTo, HWND32 hwndFrom, UINT32 uCode,
		       LPNMHDR lpHdr, DWORD dwParam5)
{
    NOTIFYDATA notify;
    HWND32 hwndNotify;

    TRACE (commctrl, "(0x%04x 0x%04x %d %p 0x%08lx)\n",
	   hwndFrom, hwndTo, uCode, lpHdr, dwParam5);

    hwndNotify = hwndTo;
    if (!hwndTo) {
	if (IsWindow32 (hwndFrom)) {
	    hwndNotify = GetParent32 (hwndFrom);
	    if (!hwndNotify)
		return 0;
	}
    }

    notify.hwndFrom = hwndFrom;
    notify.hwndTo   = hwndNotify;
    notify.dwParam5 = dwParam5;
    notify.dwParam6 = 0;

    return DoNotify (&notify, uCode, lpHdr);
}


/**************************************************************************
 * StrChrA [COMCTL32.350]
 *
 */

LPSTR WINAPI
COMCTL32_StrChrA (LPCSTR lpString, CHAR cChar)
{
    return strchr (lpString, cChar);
}


/**************************************************************************
 * StrStrIA [COMCTL32.355]
 */

LPSTR WINAPI
COMCTL32_StrStrIA (LPCSTR lpStr1, LPCSTR lpStr2)
{
    INT32 len1, len2, i;
    CHAR  first;

    if (*lpStr2 == 0)
	return ((LPSTR)lpStr1);
    len1 = 0;
    while (lpStr1[len1] != 0) ++len1;
    len2 = 0;
    while (lpStr2[len2] != 0) ++len2;
    if (len2 == 0)
	return ((LPSTR)(lpStr1 + len1));
    first = tolower (*lpStr2);
    while (len1 >= len2) {
	if (tolower(*lpStr1) == first) {
	    for (i = 1; i < len2; ++i)
		if (tolower (lpStr1[i]) != tolower(lpStr2[i]))
		    break;
	    if (i >= len2)
		return ((LPSTR)lpStr1);
        }
	++lpStr1; --len1;
    }
    return (NULL);
}


/**************************************************************************
 * StrToIntA [COMCTL32.357] Converts a string to a signed integer.
 */

INT32 WINAPI
COMCTL32_StrToIntA (LPSTR lpString)
{
    return atoi(lpString);
}


/**************************************************************************
 * COMCTL32_385 [COMCTL32.385]
 *
 * Enumerates all items in a dynamic pointer array.
 *
 * PARAMS
 *     hdpa     [I] handle to the dynamic pointer array
 *     enumProc [I]
 *     dwParam3 [I] 
 *
 * RETURNS
 *     none
 *
 * NOTES
 *     Original function name unknown!
 */

typedef DWORD (CALLBACK *DPAENUMPROC)(LPVOID, DWORD);

VOID WINAPI
COMCTL32_385 (HDPA hdpa, DPAENUMPROC enumProc, DWORD dwParam3)
{
    INT32 i;

    TRACE (commctrl, "(%p %p %08lx)\n", hdpa, enumProc, dwParam3);

    if (!hdpa)
	return;
    if (hdpa->nItemCount <= 0)
	return;

    for (i = 0; i < hdpa->nItemCount; i++) {
	if ((enumProc)(hdpa->ptrs[i], dwParam3) == 0)
	    return;
    }

    return;
}


/**************************************************************************
 * COMCTL32_386 [COMCTL32.386]
 *
 * Enumerates all items in a dynamic pointer array and destroys it.
 *
 * PARAMS
 *     hdpa     [I] handle to the dynamic pointer array
 *     enumProc [I]
 *     dwParam3 [I]
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Original function name unknown!
 */

BOOL32 WINAPI
COMCTL32_386 (HDPA hdpa, DPAENUMPROC enumProc, DWORD dwParam3)
{
    TRACE (commctrl, "(%p %p %08lx)\n", hdpa, enumProc, dwParam3);

    COMCTL32_385 (hdpa, enumProc, dwParam3);

    return DPA_Destroy (hdpa);
}


/**************************************************************************
 * COMCTL32_387 [COMCTL32.387]
 *
 * Enumerates all items in a dynamic storage array.
 *
 * PARAMS
 *     hdsa     [I] handle to the dynamic storage array
 *     enumProc [I]
 *     dwParam3 [I] 
 *
 * RETURNS
 *     none
 *
 * NOTES
 *     Original function name unknown!
 */

typedef DWORD (CALLBACK *DSAENUMPROC)(LPVOID, DWORD);

VOID WINAPI
COMCTL32_387 (HDSA hdsa, DSAENUMPROC enumProc, DWORD dwParam3)
{
    INT32 i;

    TRACE (commctrl, "(%p %p %08lx)\n", hdsa, enumProc, dwParam3);

    if (!hdsa)
	return;
    if (hdsa->nItemCount <= 0)
	return;

    for (i = 0; i < hdsa->nItemCount; i++) {
	LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
	if ((enumProc)(lpItem, dwParam3) == 0)
	    return;
    }

    return;
}


/**************************************************************************
 * COMCTL32_388 [COMCTL32.388]
 *
 * Enumerates all items in a dynamic storage array and destroys it.
 *
 * PARAMS
 *     hdsa     [I] handle to the dynamic storage array
 *     enumProc [I]
 *     dwParam3 [I] 
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Original function name unknown!
 */

BOOL32 WINAPI
COMCTL32_388 (HDSA hdsa, DSAENUMPROC enumProc, DWORD dwParam3)
{
    TRACE (commctrl, "(%p %p %08lx)\n", hdsa, enumProc, dwParam3);

    COMCTL32_387 (hdsa, enumProc, dwParam3);

    return DSA_Destroy (hdsa);
}

wine-981025/dlls/comctl32/commctrl.c100644    771    771       45744  6614330267  17066 0ustar  julliardjulliard/*		
 * Common controls functions
 *
 * Copyright 1997 Dimitrie O. Paun
 * Copyright 1998 Eric Kohl
 *
 */

#include "win.h"
#include "heap.h"
#include "commctrl.h"
#include "animate.h"
#include "comboex.h"
#include "header.h"
#include "hotkey.h"
#include "ipaddress.h"
#include "listview.h"
#include "nativefont.h"
#include "pager.h"
#include "progress.h"
#include "rebar.h"
#include "status.h"
#include "tab.h"
#include "toolbar.h"
#include "tooltips.h"
#include "trackbar.h"
#include "treeview.h"
#include "updown.h"
#include "debug.h"
#include "winerror.h"


HANDLE32 COMCTL32_hHeap = (HANDLE32)NULL;
DWORD    COMCTL32_dwProcessesAttached = 0;


/***********************************************************************
 * ComCtl32LibMain [Internal] Initializes the internal 'COMCTL32.DLL'.
 *
 * PARAMS
 *     hinstDLL    [I] handle to the 'dlls' instance
 *     fdwReason   [I]
 *     lpvReserved [I] reserverd, must be NULL
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

BOOL32 WINAPI
ComCtl32LibMain (HINSTANCE32 hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    TRACE (commctrl, "%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);

    switch (fdwReason) {
	case DLL_PROCESS_ATTACH:
	    if (COMCTL32_dwProcessesAttached == 0) {
		/* create private heap */
		COMCTL32_hHeap = HeapCreate (0, 0x10000, 0);
		TRACE (commctrl, "Heap created: 0x%x\n", COMCTL32_hHeap);

		/* register all Win95 common control classes */
		ANIMATE_Register ();
		HEADER_Register ();
		HOTKEY_Register ();
		LISTVIEW_Register ();
		PROGRESS_Register ();
		STATUS_Register ();
		TAB_Register ();
		TOOLBAR_Register ();
		TOOLTIPS_Register ();
		TRACKBAR_Register ();
		TREEVIEW_Register ();
		UPDOWN_Register ();
	    }
	    COMCTL32_dwProcessesAttached++;
	    break;

	case DLL_PROCESS_DETACH:
	    COMCTL32_dwProcessesAttached--;
	    if (COMCTL32_dwProcessesAttached == 0) {
		/* unregister all common control classes */
		ANIMATE_Unregister ();
		COMBOEX_Unregister ();
		HEADER_Unregister ();
		HOTKEY_Unregister ();
		IPADDRESS_Unregister ();
		LISTVIEW_Unregister ();
		NATIVEFONT_Unregister ();
		PAGER_Unregister ();
		PROGRESS_Unregister ();
		REBAR_Unregister ();
		STATUS_Unregister ();
		TAB_Unregister ();
		TOOLBAR_Unregister ();
		TOOLTIPS_Unregister ();
		TRACKBAR_Unregister ();
		TREEVIEW_Unregister ();
		UPDOWN_Unregister ();

		/* destroy private heap */
		HeapDestroy (COMCTL32_hHeap);
		TRACE (commctrl, "Heap destroyed: 0x%x\n", COMCTL32_hHeap);
		COMCTL32_hHeap = (HANDLE32)NULL;
	    }
	    break;
    }

    return TRUE;
}


/***********************************************************************
 * MenuHelp [COMCTL32.2]
 *
 * PARAMS
 *     uMsg       [I]
 *     wParam     [I]
 *     lParam     [I]
 *     hMainMenu  [I] handle to the applications main menu
 *     hInst      [I]
 *     hwndStatus [I] handle to the status bar window
 *     lpwIDs     [I] pointer to an array of intergers (see NOTES)
 *
 * RETURNS
 *     No return value
 *
 * NOTES
 *     The official documentation is incomplete!
 */

VOID WINAPI
MenuHelp (UINT32 uMsg, WPARAM32 wParam, LPARAM lParam, HMENU32 hMainMenu,
	  HINSTANCE32 hInst, HWND32 hwndStatus, LPUINT32 lpwIDs)
{
    UINT32 uMenuID = 0;

    if (!IsWindow32 (hwndStatus))
	return;

    switch (uMsg) {
	case WM_MENUSELECT:
	    TRACE (commctrl, "WM_MENUSELECT wParam=0x%X lParam=0x%lX\n",
		   wParam, lParam);

            if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
                /* menu was closed */
		TRACE (commctrl, "menu was closed!\n");
                SendMessage32A (hwndStatus, SB_SIMPLE, FALSE, 0);
            }
	    else {
		/* menu item was selected */
		if (HIWORD(wParam) & MF_POPUP)
		    uMenuID = (UINT32)*(lpwIDs+1);
		else
		    uMenuID = (UINT32)LOWORD(wParam);
		TRACE (commctrl, "uMenuID = %u\n", uMenuID);

		if (uMenuID) {
		    CHAR szText[256];

		    if (!LoadString32A (hInst, uMenuID, szText, 256))
			szText[0] = '\0';

		    SendMessage32A (hwndStatus, SB_SETTEXT32A,
				    255 | SBT_NOBORDERS, (LPARAM)szText);
		    SendMessage32A (hwndStatus, SB_SIMPLE, TRUE, 0);
		}
	    }
	    break;

	default:
	    FIXME (commctrl, "Invalid Message 0x%x!\n", uMsg);
	    break;
    }
}


/***********************************************************************
 * ShowHideMenuCtl [COMCTL32.3] 
 *
 * 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
 *     The official documentation is incomplete! This has been fixed.
 *
 *     lpInfo
 *     The array of integers contains pairs of values. BOTH values of
 *     the first pair must be the handles to application's main menu.
 *     Each subsequent pair consists of a menu id and control id.
 */

BOOL32 WINAPI
ShowHideMenuCtl (HWND32 hwnd, UINT32 uFlags, LPINT32 lpInfo)
{
    LPINT32 lpMenuId;

    TRACE (commctrl, "%x, %x, %p\n", hwnd, uFlags, lpInfo);

    if (lpInfo == NULL)
	return FALSE;

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

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

    if (GetMenuState32 (lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
	/* uncheck menu item */
	CheckMenuItem32 (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);

	/* hide control */
	lpMenuId++;
	SetWindowPos32 (GetDlgItem32 (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
			SWP_HIDEWINDOW);
    }
    else {
	/* check menu item */
	CheckMenuItem32 (lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);

	/* show control */
	lpMenuId++;
	SetWindowPos32 (GetDlgItem32 (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
			SWP_SHOWWINDOW);
    }

    return TRUE;
}


/***********************************************************************
 * GetEffectiveClientRect [COMCTL32.4]
 *
 * PARAMS
 *     hwnd   [I] handle to the client window.
 *     lpRect [O] pointer to the rectangle of the client window
 *     lpInfo [I] pointer to an array of integers
 *
 * RETURNS
 *     No return value.
 *
 * NOTES
 *     The official documentation is incomplete!
 */

VOID WINAPI
GetEffectiveClientRect (HWND32 hwnd, LPRECT32 lpRect, LPINT32 lpInfo)
{
    RECT32 rcCtrl;
    INT32  *lpRun;
    HWND32 hwndCtrl;

    TRACE (commctrl, "(0x%08lx 0x%08lx 0x%08lx)\n",
	   (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo);

    GetClientRect32 (hwnd, lpRect);
    lpRun = lpInfo;

    do {
	lpRun += 2;
	if (*lpRun == 0)
	    return;
	lpRun++;
	hwndCtrl = GetDlgItem32 (hwnd, *lpRun);
	if (GetWindowLong32A (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
	    TRACE (commctrl, "control id 0x%x\n", *lpRun);
	    GetWindowRect32 (hwndCtrl, &rcCtrl);
	    MapWindowPoints32 ((HWND32)0, hwnd, (LPPOINT32)&rcCtrl, 2);
	    SubtractRect32 (lpRect, lpRect, &rcCtrl);
	}
	lpRun++;
    } while (*lpRun);
}


/***********************************************************************
 * DrawStatusText32A [COMCTL32.5][COMCTL32.27]
 *
 * 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
 *     style [I]
 *
 * RETURNS
 *     No return value.
 */

VOID WINAPI
DrawStatusText32A (HDC32 hdc, LPRECT32 lprc, LPCSTR text, UINT32 style)
{
    RECT32 r = *lprc;
    UINT32 border = BDR_SUNKENOUTER;

    if (style == SBT_POPOUT)
      border = BDR_RAISEDOUTER;
    else if (style == SBT_NOBORDERS)
      border = 0;

    DrawEdge32 (hdc, &r, border, BF_RECT|BF_ADJUST|BF_MIDDLE);

    /* now draw text */
    if (text) {
      int oldbkmode = SetBkMode32 (hdc, TRANSPARENT);
      r.left += 3;
      DrawText32A (hdc, text, lstrlen32A(text),
		   &r, DT_LEFT|DT_VCENTER|DT_SINGLELINE);  
      if (oldbkmode != TRANSPARENT)
	SetBkMode32(hdc, oldbkmode);
    }
}


/***********************************************************************
 * DrawStatusText32W [COMCTL32.28]
 *
 * 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
 *     style [I]
 *
 * RETURNS
 *     No return value.
 */

VOID WINAPI
DrawStatusText32W (HDC32 hdc, LPRECT32 lprc, LPCWSTR text, UINT32 style)
{
    LPSTR p = HEAP_strdupWtoA (GetProcessHeap (), 0, text);
    DrawStatusText32A (hdc, lprc, p, style);
    HeapFree (GetProcessHeap (), 0, p );
}


/***********************************************************************
 * CreateStatusWindow32A [COMCTL32.6][COMCTL32.21] Creates a status bar
 *
 * PARAMS
 *     style  [I]
 *     text   [I]
 *     parent [I] handle to the parent window
 *     wid    [I] control id of the status bar
 *
 * RETURNS
 *     Success: handle to the control
 *     Failure: 0
 */

HWND32 WINAPI
CreateStatusWindow32A (INT32 style, LPCSTR text, HWND32 parent, UINT32 wid)
{
    return CreateWindow32A(STATUSCLASSNAME32A, text, style, 
			   CW_USEDEFAULT32, CW_USEDEFAULT32,
			   CW_USEDEFAULT32, CW_USEDEFAULT32, 
			   parent, wid, 0, 0);
}


/***********************************************************************
 * CreateStatusWindow32W [COMCTL32.22] Creates a status bar control
 *
 * PARAMS
 *     style  [I]
 *     text   [I]
 *     parent [I] handle to the parent window
 *     wid    [I] control id of the status bar
 *
 * RETURNS
 *     Success: handle to the control
 *     Failure: 0
 */

HWND32 WINAPI
CreateStatusWindow32W (INT32 style, LPCWSTR text, HWND32 parent, UINT32 wid)
{
    return CreateWindow32W((LPCWSTR)STATUSCLASSNAME32W, text, style,
			   CW_USEDEFAULT32, CW_USEDEFAULT32,
			   CW_USEDEFAULT32, CW_USEDEFAULT32,
			   parent, wid, 0, 0);
}


/***********************************************************************
 * CreateUpDownControl [COMCTL32.16] Creates an Up-Down control
 *
 * PARAMS
 *     style
 *     x
 *     y
 *     cx
 *     cy
 *     parent
 *     id
 *     inst
 *     buddy
 *     maxVal [I]
 *     minVal [I]
 *     curVal [I]
 *
 * RETURNS
 *     Success: handle to the control
 *     Failure: 0
 */

HWND32 WINAPI
CreateUpDownControl (DWORD style, INT32 x, INT32 y, INT32 cx, INT32 cy,
		     HWND32 parent, INT32 id, HINSTANCE32 inst,
		     HWND32 buddy, INT32 maxVal, INT32 minVal, INT32 curVal)
{
    HWND32 hUD =
	CreateWindow32A (UPDOWN_CLASS32A, 0, style, x, y, cx, cy,
			 parent, id, inst, 0);
    if (hUD) {
	SendMessage32A (hUD, UDM_SETBUDDY, buddy, 0);
	SendMessage32A (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
	SendMessage32A (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));     
    }

    return hUD;
}


/***********************************************************************
 * InitCommonControls [COMCTL32.17]
 *
 * Registers the common controls.
 *
 * PARAMS
 *     No parameters.
 *
 * RETURNS
 *     No return values.
 *
 * NOTES
 *     This function is just a dummy.
 *     The Win95 controls are registered at the DLL's initialization.
 *     To register other controls InitCommonControlsEx must be used.
 */

VOID WINAPI
InitCommonControls (VOID)
{
}


/***********************************************************************
 * InitCommonControlsEx [COMCTL32.81]
 *
 * Registers the common controls.
 *
 * PARAMS
 *     lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Only the additinal common controls are registered by this function.
 *     The Win95 controls are registered at the DLL's initialization.
 */

BOOL32 WINAPI
InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls)
{
    INT32 cCount;
    DWORD dwMask;

    if (!lpInitCtrls)
	return FALSE;
    if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
	return FALSE;

    TRACE(commctrl,"(0x%08lx)\n", lpInitCtrls->dwICC);

    for (cCount = 0; cCount < 32; cCount++) {
	dwMask = 1 << cCount;
	if (!(lpInitCtrls->dwICC & dwMask))
	    continue;

	switch (lpInitCtrls->dwICC & dwMask) {
	    /* dummy initialization */
	    case ICC_ANIMATE_CLASS:
	    case ICC_BAR_CLASSES:
	    case ICC_LISTVIEW_CLASSES:
	    case ICC_TREEVIEW_CLASSES:
	    case ICC_TAB_CLASSES:
	    case ICC_UPDOWN_CLASS:
	    case ICC_PROGRESS_CLASS:
	    case ICC_HOTKEY_CLASS:
		break;

	    /* advanced classes - not included in Win95 */
	    case ICC_DATE_CLASSES:
		FIXME (commctrl, "No month calendar class implemented!\n");
		FIXME (commctrl, "No date and time picker class implemented!\n");
		break;

	    case ICC_USEREX_CLASSES:
		COMBOEX_Register ();
		break;

	    case ICC_COOL_CLASSES:
		REBAR_Register ();
		break;

	    case ICC_INTERNET_CLASSES:
		IPADDRESS_Register ();
		break;

	    case ICC_PAGESCROLLER_CLASS:
		PAGER_Register ();
		break;

	    case ICC_NATIVEFNTCTL_CLASS:
		NATIVEFONT_Register ();
		break;

	    default:
		FIXME (commctrl, "Unknown class! dwICC=0x%lX\n", dwMask);
		break;
	}
    }

    return TRUE;
}


/***********************************************************************
 * CreateToolbarEx [COMCTL32.32] Creates a tool bar window
 *
 * PARAMS
 *     hwnd
 *     style
 *     wID
 *     nBitmaps
 *     hBMInst
 *     wBMID
 *     lpButtons
 *     iNumButtons
 *     dxButton
 *     dyButton
 *     dxBitmap
 *     dyBitmap
 *     uStructSize
 *
 * RETURNS
 *     Success: handle to the tool bar control
 *     Failure: 0
 */

HWND32 WINAPI
CreateToolbarEx (HWND32 hwnd, DWORD style, UINT32 wID, INT32 nBitmaps,
                 HINSTANCE32 hBMInst, UINT32 wBMID, LPCTBBUTTON lpButtons,
                 INT32 iNumButtons, INT32 dxButton, INT32 dyButton,
                 INT32 dxBitmap, INT32 dyBitmap, UINT32 uStructSize)
{
    HWND32 hwndTB =
        CreateWindowEx32A (0, TOOLBARCLASSNAME32A, "", style, 0, 0, 0, 0,
			   hwnd, (HMENU32)wID, 0, NULL);
    if(hwndTB) {
	TBADDBITMAP tbab;

        SendMessage32A (hwndTB, TB_BUTTONSTRUCTSIZE,
			(WPARAM32)uStructSize, 0);

	/* set bitmap and button size */
	if (hBMInst == HINST_COMMCTRL) {
	    if (wBMID & 1) {
		SendMessage32A (hwndTB, TB_SETBITMAPSIZE, 0,
				MAKELPARAM(26, 25));
		SendMessage32A (hwndTB, TB_SETBUTTONSIZE, 0,
				MAKELPARAM(33, 32));
	    }
	    else {
		SendMessage32A (hwndTB, TB_SETBITMAPSIZE, 0,
				MAKELPARAM(16, 15));
		SendMessage32A (hwndTB, TB_SETBUTTONSIZE, 0,
				MAKELPARAM(23, 22));
	    }
	}
	else {
	    SendMessage32A (hwndTB, TB_SETBITMAPSIZE, 0,
			    MAKELPARAM((WORD)dyBitmap, (WORD)dxBitmap));
	    SendMessage32A (hwndTB, TB_SETBUTTONSIZE, 0,
			    MAKELPARAM((WORD)dyButton, (WORD)dxButton));
	}

	/* add bitmaps */
	tbab.hInst = hBMInst;
	tbab.nID   = wBMID;
	SendMessage32A (hwndTB, TB_ADDBITMAP,
			(WPARAM32)nBitmaps, (LPARAM)&tbab);

	/* add buttons */
	SendMessage32A (hwndTB, TB_ADDBUTTONS32A,
			(WPARAM32)iNumButtons, (LPARAM)lpButtons);
    }

    return hwndTB;
}


/***********************************************************************
 * CreateMappedBitmap [COMCTL32.8]
 *
 * PARAMS
 *     hInstance
 *     idBitmap
 *     wFlags
 *     lpColorMap
 *     iNumMaps
 *
 * RETURNS
 *     Success: bitmap handle
 *     Failure: 0
 */

HBITMAP32 WINAPI
CreateMappedBitmap (HINSTANCE32 hInstance, INT32 idBitmap, UINT32 wFlags,
		    LPCOLORMAP lpColorMap, INT32 iNumMaps)
{
    HGLOBAL32 hglb;
    HRSRC32 hRsrc;
    LPBITMAPINFOHEADER lpBitmap, lpBitmapInfo;
    UINT32 nSize, nColorTableSize;
    DWORD *pColorTable;
    INT32 iColor, i, iMaps, nWidth, nHeight;
    HDC32 hdcScreen;
    HBITMAP32 hbm;
    LPCOLORMAP sysColorMap;
    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 {
	internalColorMap[0].to = GetSysColor32 (COLOR_BTNTEXT);
	internalColorMap[1].to = GetSysColor32 (COLOR_BTNSHADOW);
	internalColorMap[2].to = GetSysColor32 (COLOR_BTNFACE);
	internalColorMap[3].to = GetSysColor32 (COLOR_BTNHIGHLIGHT);
	iMaps = 4;
	sysColorMap = (LPCOLORMAP)internalColorMap;
    }

    hRsrc = FindResource32A (hInstance, (LPSTR)idBitmap, RT_BITMAP32A);
    if (hRsrc == 0)
	return 0;
    hglb = LoadResource32 (hInstance, hRsrc);
    if (hglb == 0)
	return 0;
    lpBitmap = (LPBITMAPINFOHEADER)LockResource32 (hglb);
    if (lpBitmap == NULL)
	return 0;

    nColorTableSize = (1 << lpBitmap->biBitCount);
    nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
    lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc32 (GMEM_FIXED, nSize);
    if (lpBitmapInfo == NULL)
	return 0;
    RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);

    pColorTable = (DWORD*)(((LPBYTE)lpBitmapInfo)+(UINT32)lpBitmapInfo->biSize);

    for (iColor = 0; iColor < nColorTableSize; iColor++) {
	for (i = 0; i < iMaps; i++) {
	    if (pColorTable[iColor] == sysColorMap[i].from) {
#if 0
		if (wFlags & CBS_MASKED) {
		    if (sysColorMap[i].to != COLOR_BTNTEXT)
			pColorTable[iColor] = RGB(255, 255, 255);
		}
		else
#endif
		    pColorTable[iColor] = sysColorMap[i].to;
		break;
	    }
	}
    }

    nWidth  = (INT32)lpBitmapInfo->biWidth;
    nHeight = (INT32)lpBitmapInfo->biHeight;
    hdcScreen = GetDC32 ((HWND32)0);
    hbm = CreateCompatibleBitmap32 (hdcScreen, nWidth, nHeight);
    if (hbm) {
	HDC32 hdcDst = CreateCompatibleDC32 (hdcScreen);
	HBITMAP32 hbmOld = SelectObject32 (hdcDst, hbm);
	LPBYTE lpBits = (LPBYTE)(lpBitmap + 1);
	lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
	StretchDIBits32 (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
		         lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
		         SRCCOPY);
	SelectObject32 (hdcDst, hbmOld);
	DeleteDC32 (hdcDst);
    }
    ReleaseDC32 ((HWND32)0, hdcScreen);
    GlobalFree32 ((HGLOBAL32)lpBitmapInfo);
    FreeResource32 (hglb);

    return hbm;
}


/***********************************************************************
 * CreateToolbar [COMCTL32.7] Creates a tool bar control
 *
 * PARAMS
 *     hwnd
 *     style
 *     wID
 *     nBitmaps
 *     hBMInst
 *     wBMID
 *     lpButtons
 *     iNumButtons
 *
 * RETURNS
 *     Success: handle to the tool bar control
 *     Failure: 0
 *
 * NOTES
 *     Do not use this functions anymore. Use CreateToolbarEx instead.
 */

HWND32 WINAPI
CreateToolbar (HWND32 hwnd, DWORD style, UINT32 wID, INT32 nBitmaps,
	       HINSTANCE32 hBMInst, UINT32 wBMID,
	       LPCOLDTBBUTTON lpButtons,INT32 iNumButtons)
{
    return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
			    hBMInst, wBMID, (LPCTBBUTTON)lpButtons,
			    iNumButtons, 0, 0, 0, 0, sizeof (OLDTBBUTTON));
}


/***********************************************************************
 * DllGetVersion [COMCTL32.25]
 *
 * Retrieves version information of the 'COMCTL32.DLL'
 *
 * PARAMS
 *     pdvi [O] pointer to version information structure.
 *
 * RETURNS
 *     Success: S_OK
 *     Failure: E_INVALIDARG
 *
 * NOTES
 *     Returns version of a comctl32.dll from IE4.01 SP1.
 */

HRESULT WINAPI
COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi)
{
    if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) {
        WARN (commctrl, "wrong DLLVERSIONINFO size from app");
	return E_INVALIDARG;
    }

    pdvi->dwMajorVersion = 4;
    pdvi->dwMinorVersion = 72;
    pdvi->dwBuildNumber = 3110;
    pdvi->dwPlatformID = 1;

    TRACE (commctrl, "%lu.%lu.%lu.%lu\n",
	   pdvi->dwMajorVersion, pdvi->dwMinorVersion,
	   pdvi->dwBuildNumber, pdvi->dwPlatformID);

    return S_OK;
}
wine-981025/dlls/comctl32/header.c100644    771    771      102207  6614330267  16502 0ustar  julliardjulliard/*
 *  Header control
 *
 *  Copyright 1998 Eric Kohl
 *
 *  TODO:
 *   - Imagelist support (partially).
 *   - Callback items (under construction).
 *   - Order list support.
 *   - Control specific cursors (over dividers).
 *   - Hottrack support (partially).
 *   - Custom draw support (including Notifications).
 *   - Drag and Drop support (including Notifications).
 *   - Unicode support.
 *
 *  FIXME:
 *   - Replace DrawText32A by DrawTextEx32A(...|DT_ENDELLIPSIS) in
 *     HEADER_DrawItem.
 *   - Little flaw when drawing a bitmap on the right side of the text.
 */

#include "windows.h"
#include "commctrl.h"
#include "header.h"
#include "win.h"
#include "debug.h"


#define __HDM_LAYOUT_HACK__


#define VERT_BORDER     4
#define DIVIDER_WIDTH  10

#define HEADER_GetInfoPtr(wndPtr) ((HEADER_INFO *)wndPtr->wExtra[0])


static INT32
HEADER_DrawItem (WND *wndPtr, HDC32 hdc, INT32 iItem, BOOL32 bHotTrack)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HEADER_ITEM *phdi = &infoPtr->items[iItem];
    RECT32 r;
    INT32  oldBkMode;

    r = phdi->rect;
    if (r.right - r.left == 0)
	return phdi->rect.right;

    if (wndPtr->dwStyle & HDS_BUTTONS) {
	if (phdi->bDown) {
	    DrawEdge32 (hdc, &r, BDR_RAISEDOUTER,
			BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST);
	    r.left += 2;
            r.top  += 2;
	}
	else
	    DrawEdge32 (hdc, &r, EDGE_RAISED,
			BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
    }
    else
        DrawEdge32 (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);

    if (phdi->fmt & HDF_OWNERDRAW) {
	DRAWITEMSTRUCT32 dis;
	dis.CtlType    = ODT_HEADER;
	dis.CtlID      = wndPtr->wIDmenu;
	dis.itemID     = iItem;
	dis.itemAction = ODA_DRAWENTIRE;
	dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
	dis.hwndItem   = wndPtr->hwndSelf;
	dis.hDC        = hdc;
	dis.rcItem     = r;
	dis.itemData   = phdi->lParam;
	SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_DRAWITEM,
			(WPARAM32)wndPtr->wIDmenu, (LPARAM)&dis);
    }
    else {
        UINT32 uTextJustify = DT_LEFT;

        if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
            uTextJustify = DT_CENTER;
        else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
            uTextJustify = DT_RIGHT;

	if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) {
	    BITMAP32 bmp;
	    HDC32    hdcBitmap;
	    INT32    yD, yS, cx, cy, rx, ry;

	    GetObject32A (phdi->hbm, sizeof(BITMAP32), (LPVOID)&bmp);

	    ry = r.bottom - r.top;
	    rx = r.right - r.left;

	    if (ry >= bmp.bmHeight) {
		cy = bmp.bmHeight;
		yD = r.top + (ry - bmp.bmHeight) / 2;
		yS = 0;
	    }
	    else {
		cy = ry;
		yD = r.top;
		yS = (bmp.bmHeight - ry) / 2;

	    }

	    if (rx >= bmp.bmWidth + 6) {
		cx = bmp.bmWidth;
	    }
	    else {
		cx = rx - 6;
	    }

	    hdcBitmap = CreateCompatibleDC32 (hdc);
	    SelectObject32 (hdcBitmap, phdi->hbm);
	    BitBlt32 (hdc, r.left + 3, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY);
	    DeleteDC32 (hdcBitmap);

	    r.left += (bmp.bmWidth + 3);
	}


	if ((phdi->fmt & HDF_BITMAP_ON_RIGHT) && (phdi->hbm)) {
	    BITMAP32 bmp;
	    HDC32    hdcBitmap;
	    INT32    xD, yD, yS, cx, cy, rx, ry, tx;
	    RECT32   textRect;

	    GetObject32A (phdi->hbm, sizeof(BITMAP32), (LPVOID)&bmp);

	    textRect = r;
            DrawText32A(hdc, phdi->pszText, lstrlen32A(phdi->pszText),
	   	  &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
	    tx = textRect.right - textRect.left;
	    ry = r.bottom - r.top;
	    rx = r.right - r.left;

	    if (ry >= bmp.bmHeight) {
		cy = bmp.bmHeight;
		yD = r.top + (ry - bmp.bmHeight) / 2;
		yS = 0;
	    }
	    else {
		cy = ry;
		yD = r.top;
		yS = (bmp.bmHeight - ry) / 2;

	    }

	    if (r.left + tx + bmp.bmWidth + 9 <= r.right) {
		cx = bmp.bmWidth;
		xD = r.left + tx + 6;
	    }
	    else {
		if (rx >= bmp.bmWidth + 6) {
		    cx = bmp.bmWidth;
		    xD = r.right - bmp.bmWidth - 3;
		    r.right = xD - 3;
		}
		else {
		    cx = rx - 3;
		    xD = r.left;
		    r.right = r.left;
		}
	    }

	    hdcBitmap = CreateCompatibleDC32 (hdc);
	    SelectObject32 (hdcBitmap, phdi->hbm);
	    BitBlt32 (hdc, xD, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY);
	    DeleteDC32 (hdcBitmap);
	}

	if (phdi->fmt & HDF_IMAGE) {


//	    ImageList_Draw (infoPtr->himl, phdi->iImage,...);
	}

        if ((phdi->fmt & HDF_STRING) && (phdi->pszText)) {
            oldBkMode = SetBkMode32(hdc, TRANSPARENT);
            r.left += 3;
	    r.right -= 3;
	    SetTextColor32 (hdc, bHotTrack ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
            DrawText32A(hdc, phdi->pszText, lstrlen32A(phdi->pszText),
	   	  &r, uTextJustify|DT_VCENTER|DT_SINGLELINE);
            if (oldBkMode != TRANSPARENT)
                SetBkMode32(hdc, oldBkMode);
        }
    }
    return phdi->rect.right;
}


static void 
HEADER_Refresh (WND *wndPtr, HDC32 hdc)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HFONT32 hFont, hOldFont;
    RECT32 rect;
    HBRUSH32 hbrBk;
    INT32 i, x;

    /* get rect for the bar, adjusted for the border */
    GetClientRect32 (wndPtr->hwndSelf, &rect);

    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
    hOldFont = SelectObject32 (hdc, hFont);

    /* draw Background */
    hbrBk = GetSysColorBrush32(COLOR_3DFACE);
    FillRect32(hdc, &rect, hbrBk);

    x = rect.left;
    for (i = 0; i < infoPtr->uNumItem; i++) {
        x = HEADER_DrawItem (wndPtr, hdc, i, FALSE);
    }

    if ((x <= rect.right) && (infoPtr->uNumItem > 0)) {
        rect.left = x;
        if (wndPtr->dwStyle & HDS_BUTTONS)
            DrawEdge32 (hdc, &rect, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT);
        else
            DrawEdge32 (hdc, &rect, EDGE_ETCHED, BF_BOTTOM);
    }

    SelectObject32 (hdc, hOldFont);
}


static void
HEADER_RefreshItem (WND *wndPtr, HDC32 hdc, INT32 iItem)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HFONT32 hFont, hOldFont;

    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
    hOldFont = SelectObject32 (hdc, hFont);
    HEADER_DrawItem (wndPtr, hdc, iItem, FALSE);
    SelectObject32 (hdc, hOldFont);
}


static void
HEADER_SetItemBounds (WND *wndPtr)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HEADER_ITEM *phdi;
    RECT32 rect;
    int i, x;

    if (infoPtr->uNumItem == 0)
        return;

    GetClientRect32 (wndPtr->hwndSelf, &rect);

    x = rect.left;
    for (i = 0; i < infoPtr->uNumItem; i++) {
        phdi = &infoPtr->items[i];
        phdi->rect.top = rect.top;
        phdi->rect.bottom = rect.bottom;
        phdi->rect.left = x;
        phdi->rect.right = phdi->rect.left + phdi->cxy;
        x = phdi->rect.right;
    }
}


static void
HEADER_ForceItemBounds (WND *wndPtr, INT32 cy)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HEADER_ITEM *phdi;
    int i, x;

    if (infoPtr->uNumItem == 0)
	return;

    x = 0;
    for (i = 0; i < infoPtr->uNumItem; i++) {
	phdi = &infoPtr->items[i];
	phdi->rect.top = 0;
	phdi->rect.bottom = cy;
	phdi->rect.left = x;
	phdi->rect.right = phdi->rect.left + phdi->cxy;
	x = phdi->rect.right;
    }
}


static void
HEADER_InternalHitTest (WND *wndPtr, LPPOINT32 lpPt, UINT32 *pFlags, INT32 *pItem)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    RECT32 rect, rcTest;
    INT32  iCount, width;
    BOOL32 bNoWidth;

    GetClientRect32 (wndPtr->hwndSelf, &rect);

    *pFlags = 0;
    bNoWidth = FALSE;
    if (PtInRect32 (&rect, *lpPt))
    {
	if (infoPtr->uNumItem == 0) {
	    *pFlags |= HHT_NOWHERE;
	    *pItem = 1;
	    TRACE (header, "NOWHERE\n");
	    return;
	}
	else {
	    /* somewhere inside */
	    for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
		rect = infoPtr->items[iCount].rect;
		width = rect.right - rect.left;
		if (width == 0) {
		    bNoWidth = TRUE;
		    continue;
		}
		if (PtInRect32 (&rect, *lpPt)) {
		    if (width <= 2 * DIVIDER_WIDTH) {
			*pFlags |= HHT_ONHEADER;
			*pItem = iCount;
			TRACE (header, "ON HEADER %d\n", iCount);
			return;
		    }
		    if (iCount > 0) {
			rcTest = rect;
			rcTest.right = rcTest.left + DIVIDER_WIDTH;
			if (PtInRect32 (&rcTest, *lpPt)) {
			    if (bNoWidth) {
				*pFlags |= HHT_ONDIVOPEN;
				*pItem = iCount - 1;
				TRACE (header, "ON DIVOPEN %d\n", *pItem);
				return;
			    }
			    else {
				*pFlags |= HHT_ONDIVIDER;
				*pItem = iCount - 1;
				TRACE (header, "ON DIVIDER %d\n", *pItem);
				return;
			    }
			}
		    }
		    rcTest = rect;
		    rcTest.left = rcTest.right - DIVIDER_WIDTH;
		    if (PtInRect32 (&rcTest, *lpPt)) {
			*pFlags |= HHT_ONDIVIDER;
			*pItem = iCount;
			TRACE (header, "ON DIVIDER %d\n", *pItem);
			return;
		    }

		    *pFlags |= HHT_ONHEADER;
		    *pItem = iCount;
		    TRACE (header, "ON HEADER %d\n", iCount);
		    return;
		}
	    }

	    /* check for last divider part (on nowhere) */
	    rect = infoPtr->items[infoPtr->uNumItem-1].rect;
	    rect.left = rect.right;
	    rect.right += DIVIDER_WIDTH;
	    if (PtInRect32 (&rect, *lpPt)) {
		if (bNoWidth) {
		    *pFlags |= HHT_ONDIVOPEN;
		    *pItem = infoPtr->uNumItem - 1;
		    TRACE (header, "ON DIVOPEN %d\n", *pItem);
		    return;
		}
		else {
		    *pFlags |= HHT_ONDIVIDER;
		    *pItem = infoPtr->uNumItem-1;
		    TRACE (header, "ON DIVIDER %d\n", *pItem);
		    return;
		}
	    }

	    *pFlags |= HHT_NOWHERE;
	    *pItem = 1;
	    TRACE (header, "NOWHERE\n");
	    return;
	}
    }
    else {
	if (lpPt->x < rect.left) {
	   TRACE (header, "TO LEFT\n");
	   *pFlags |= HHT_TOLEFT;
	}
	else if (lpPt->x > rect.right) {
	    TRACE (header, "TO LEFT\n");
	    *pFlags |= HHT_TORIGHT;
	}

	if (lpPt->y < rect.top) {
	    TRACE (header, "ABOVE\n");
	    *pFlags |= HHT_ABOVE;
	}
	else if (lpPt->y > rect.bottom) {
	    TRACE (header, "BELOW\n");
	    *pFlags |= HHT_BELOW;
	}
    }

    *pItem = 1;
    TRACE (header, "flags=0x%X\n", *pFlags);
    return;
}


static void
HEADER_DrawTrackLine (WND *wndPtr, HDC32 hdc, INT32 x)
{
    RECT32 rect;
    HPEN32 hOldPen;
    INT32  oldRop;

    GetClientRect32 (wndPtr->hwndSelf, &rect);

    hOldPen = SelectObject32 (hdc, GetStockObject32 (BLACK_PEN));
    oldRop = SetROP232 (hdc, R2_XORPEN);
    MoveToEx32 (hdc, x, rect.top, NULL);
    LineTo32 (hdc, x, rect.bottom);
    SetROP232 (hdc, oldRop);
    SelectObject32 (hdc, hOldPen);
}


static BOOL32
HEADER_SendSimpleNotify (WND *wndPtr, UINT32 code)
{
    NMHDR nmhdr;

    nmhdr.hwndFrom = wndPtr->hwndSelf;
    nmhdr.idFrom   = wndPtr->wIDmenu;
    nmhdr.code     = code;

    return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
				   (WPARAM32)nmhdr.idFrom, (LPARAM)&nmhdr);
}


static BOOL32
HEADER_SendHeaderNotify (WND *wndPtr, UINT32 code, INT32 iItem)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);   
    NMHEADER32A nmhdr;
    HDITEM32A nmitem;

    nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
    nmhdr.hdr.idFrom = wndPtr->wIDmenu;
    nmhdr.hdr.code = code;
    nmhdr.iItem = iItem;
    nmhdr.iButton = 0;
    nmhdr.pitem = &nmitem;
    nmitem.mask = 0;
    nmitem.cxy = infoPtr->items[iItem].cxy;
    nmitem.hbm = infoPtr->items[iItem].hbm;
    nmitem.pszText = NULL;
    nmitem.cchTextMax = 0;
//    nmitem.pszText = infoPtr->items[iItem].pszText;
//    nmitem.cchTextMax = infoPtr->items[iItem].cchTextMax;
    nmitem.fmt = infoPtr->items[iItem].fmt;
    nmitem.lParam = infoPtr->items[iItem].lParam;
    nmitem.iOrder = infoPtr->items[iItem].iOrder;
    nmitem.iImage = infoPtr->items[iItem].iImage;

    return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
				   (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmhdr);
}


static BOOL32
HEADER_SendClickNotify (WND *wndPtr, UINT32 code, INT32 iItem)
{
    NMHEADER32A nmhdr;

    nmhdr.hdr.hwndFrom = wndPtr->hwndSelf;
    nmhdr.hdr.idFrom = wndPtr->wIDmenu;
    nmhdr.hdr.code = code;
    nmhdr.iItem = iItem;
    nmhdr.iButton = 0;
    nmhdr.pitem = NULL;

    return (BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
				   (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmhdr);
}


static LRESULT
HEADER_CreateDragImage (WND *wndPtr, WPARAM32 wParam)
{
    FIXME (header, "empty stub!\n");
    return 0;
}


static LRESULT
HEADER_DeleteItem (WND *wndPtr, WPARAM32 wParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    INT32 iItem = (INT32)wParam;
    HDC32 hdc;

    TRACE(header, "[iItem=%d]\n", iItem);
    
    if ((iItem < 0) || (iItem >= (INT32)infoPtr->uNumItem))
        return FALSE;

    if (infoPtr->uNumItem == 1) {
        TRACE(header, "Simple delete!\n");
        if (infoPtr->items[0].pszText)
            COMCTL32_Free (infoPtr->items[0].pszText);
        COMCTL32_Free (infoPtr->items);
        infoPtr->items = 0;
        infoPtr->uNumItem = 0;
    }
    else {
        HEADER_ITEM *oldItems = infoPtr->items;
        TRACE(header, "Complex delete! [iItem=%d]\n", iItem);

        if (infoPtr->items[iItem].pszText)
            COMCTL32_Free (infoPtr->items[iItem].pszText);

        infoPtr->uNumItem--;
        infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
        /* pre delete copy */
        if (iItem > 0) {
            memcpy (&infoPtr->items[0], &oldItems[0],
                    iItem * sizeof(HEADER_ITEM));
        }

        /* post delete copy */
        if (iItem < infoPtr->uNumItem) {
            memcpy (&infoPtr->items[iItem], &oldItems[iItem+1],
                    (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM));
        }

        COMCTL32_Free (oldItems);
    }

    HEADER_SetItemBounds (wndPtr);

    hdc = GetDC32 (wndPtr->hwndSelf);
    HEADER_Refresh (wndPtr, hdc);
    ReleaseDC32 (wndPtr->hwndSelf, hdc);
    
    return TRUE;
}


static LRESULT
HEADER_GetImageList (WND *wndPtr)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);

    return (LRESULT)infoPtr->himl;
}


static LRESULT
HEADER_GetItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HDITEM32A   *phdi = (HDITEM32A*)lParam;
    INT32       nItem = (INT32)wParam;
    HEADER_ITEM *lpItem;

    if (!phdi)
	return FALSE;
    if ((nItem < 0) || (nItem >= (INT32)infoPtr->uNumItem))
        return FALSE;

    TRACE (header, "[nItem=%d]\n", nItem);

    if (phdi->mask == 0)
	return TRUE;

    lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
    if (phdi->mask & HDI_BITMAP)
	phdi->hbm = lpItem->hbm;

    if (phdi->mask & HDI_FORMAT)
	phdi->fmt = lpItem->fmt;

    if (phdi->mask & HDI_WIDTH)
	phdi->cxy = lpItem->cxy;

    if (phdi->mask & HDI_LPARAM)
	phdi->lParam = lpItem->lParam;

    if (phdi->mask & HDI_TEXT) {
	if (lpItem->pszText != LPSTR_TEXTCALLBACK32A)
	    lstrcpyn32A (phdi->pszText, lpItem->pszText, phdi->cchTextMax);
	else
	    phdi->pszText = LPSTR_TEXTCALLBACK32A;
    }

    if (phdi->mask & HDI_IMAGE)
	phdi->iImage = lpItem->iImage;

    if (phdi->mask & HDI_ORDER)
	phdi->iOrder = lpItem->iOrder;

    return TRUE;
}


static LRESULT
HEADER_GetItemCount (WND *wndPtr)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);

    return (infoPtr->uNumItem);
}


static LRESULT
HEADER_GetItemRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    INT32 iItem = (INT32)wParam;
    LPRECT32 lpRect = (LPRECT32)lParam;

    if ((iItem < 0) || (iItem >= (INT32)infoPtr->uNumItem))
        return FALSE;

    lpRect->left   = infoPtr->items[iItem].rect.left;
    lpRect->right  = infoPtr->items[iItem].rect.right;
    lpRect->top    = infoPtr->items[iItem].rect.top;
    lpRect->bottom = infoPtr->items[iItem].rect.bottom;

    return TRUE;
}


static LRESULT
HEADER_HitTest (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam;

    HEADER_InternalHitTest (wndPtr, &phti->pt, &phti->flags, &phti->iItem);

    return phti->flags;
}


static LRESULT
HEADER_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HDITEM32A   *phdi = (HDITEM32A*)lParam;
    INT32       nItem = (INT32)wParam;
    HEADER_ITEM *lpItem;
    HDC32       hdc;
    INT32       len;

    if ((phdi == NULL) || (nItem < 0))
	return -1;

    if (nItem > infoPtr->uNumItem)
        nItem = infoPtr->uNumItem;

    if (infoPtr->uNumItem == 0) {
        infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM));
        infoPtr->uNumItem++;
    }
    else {
        HEADER_ITEM *oldItems = infoPtr->items;

        infoPtr->uNumItem++;
        infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
        /* pre insert copy */
        if (nItem > 0) {
            memcpy (&infoPtr->items[0], &oldItems[0],
                    nItem * sizeof(HEADER_ITEM));
        }

        /* post insert copy */
        if (nItem < infoPtr->uNumItem - 1) {
            memcpy (&infoPtr->items[nItem+1], &oldItems[nItem],
                    (infoPtr->uNumItem - nItem) * sizeof(HEADER_ITEM));
        }

	COMCTL32_Free (oldItems);
    }

    lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
    lpItem->bDown = FALSE;

    if (phdi->mask & HDI_WIDTH)
	lpItem->cxy = phdi->cxy;

    if (phdi->mask & HDI_TEXT) {
	if (phdi->pszText != LPSTR_TEXTCALLBACK32A) {
	    len = lstrlen32A (phdi->pszText);
	    lpItem->pszText = COMCTL32_Alloc (len+1);
	    lstrcpy32A (lpItem->pszText, phdi->pszText);
	}
	else
	    lpItem->pszText = LPSTR_TEXTCALLBACK32A;
    }

    if (phdi->mask & HDI_FORMAT)
	lpItem->fmt = phdi->fmt;

    if (lpItem->fmt == 0)
	lpItem->fmt = HDF_LEFT;

    if (phdi->mask & HDI_BITMAP)
        lpItem->hbm = phdi->hbm;

    if (phdi->mask & HDI_LPARAM)
        lpItem->lParam = phdi->lParam;

    if (phdi->mask & HDI_IMAGE)
        lpItem->iImage = phdi->iImage;

    if (phdi->mask & HDI_ORDER)
        lpItem->iOrder = phdi->iOrder;

    HEADER_SetItemBounds (wndPtr);

    hdc = GetDC32 (wndPtr->hwndSelf);
    HEADER_Refresh (wndPtr, hdc);
    ReleaseDC32 (wndPtr->hwndSelf, hdc);

    return nItem;
}


static LRESULT
HEADER_Layout (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam;

    lpLayout->pwpos->hwnd = wndPtr->hwndSelf;
    lpLayout->pwpos->hwndInsertAfter = 0;
    lpLayout->pwpos->x = lpLayout->prc->left;
    lpLayout->pwpos->y = lpLayout->prc->top;
    lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
    if (wndPtr->dwStyle & HDS_HIDDEN)
        lpLayout->pwpos->cy = 0;
    else
        lpLayout->pwpos->cy = infoPtr->nHeight;
    lpLayout->pwpos->flags = SWP_NOZORDER;

    TRACE (header, "Layout x=%d y=%d cx=%d cy=%d\n",
           lpLayout->pwpos->x, lpLayout->pwpos->y,
           lpLayout->pwpos->cx, lpLayout->pwpos->cy);

    HEADER_ForceItemBounds (wndPtr, lpLayout->pwpos->cy);

    /* hack */
#ifdef __HDM_LAYOUT_HACK__
    MoveWindow32 (lpLayout->pwpos->hwnd, lpLayout->pwpos->x, lpLayout->pwpos->y,
                  lpLayout->pwpos->cx, lpLayout->pwpos->cy, TRUE);
#endif

    return TRUE;
}


static LRESULT
HEADER_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HIMAGELIST himlOld;

    himlOld = infoPtr->himl;
    infoPtr->himl = (HIMAGELIST)lParam;

    /* FIXME: Refresh needed??? */

    return (LRESULT)himlOld;
}


static LRESULT
HEADER_SetItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HDITEM32A *phdi = (HDITEM32A*)lParam;
    INT32 nItem = (INT32)wParam;
    HEADER_ITEM *lpItem;
    HDC32 hdc;

    if (phdi == NULL)
	return FALSE;
    if ((nItem < 0) || (nItem >= (INT32)infoPtr->uNumItem))
        return FALSE;

    TRACE (header, "[nItem=%d]\n", nItem);

    if (HEADER_SendHeaderNotify (wndPtr, HDN_ITEMCHANGING32A, nItem))
	return FALSE;

    lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
    if (phdi->mask & HDI_BITMAP)
	lpItem->hbm = phdi->hbm;

    if (phdi->mask & HDI_FORMAT)
	lpItem->fmt = phdi->fmt;

    if (phdi->mask & HDI_LPARAM)
	lpItem->lParam = phdi->lParam;

    if (phdi->mask & HDI_TEXT) {
	if (phdi->pszText != LPSTR_TEXTCALLBACK32A) {
	    INT32 len = lstrlen32A (phdi->pszText);
	    if (lpItem->pszText)
		COMCTL32_Free (lpItem->pszText);
	    lpItem->pszText = COMCTL32_Alloc (len+1);
	    lstrcpy32A (lpItem->pszText, phdi->pszText);
	}
	else
	    lpItem->pszText = LPSTR_TEXTCALLBACK32A;
    }

    if (phdi->mask & HDI_WIDTH)
	lpItem->cxy = phdi->cxy;

    if (phdi->mask & HDI_IMAGE)
	lpItem->iImage = phdi->iImage;

    if (phdi->mask & HDI_ORDER)
	lpItem->iOrder = phdi->iOrder;

    HEADER_SendHeaderNotify (wndPtr, HDN_ITEMCHANGED32A, nItem);

    HEADER_SetItemBounds (wndPtr);
    hdc = GetDC32 (wndPtr->hwndSelf);
    HEADER_Refresh (wndPtr, hdc);
    ReleaseDC32 (wndPtr->hwndSelf, hdc);

    return TRUE;
}


static LRESULT
HEADER_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr;
    TEXTMETRIC32A tm;
    HFONT32 hOldFont;
    HDC32   hdc;

    infoPtr = (HEADER_INFO *)COMCTL32_Alloc (sizeof(HEADER_INFO));
    wndPtr->wExtra[0] = (DWORD)infoPtr;

    infoPtr->uNumItem = 0;
    infoPtr->nHeight = 20;
    infoPtr->hFont = 0;
    infoPtr->items = 0;
    infoPtr->hcurArrow = LoadCursor32A (0, IDC_ARROW32A);
    infoPtr->hcurDivider = LoadCursor32A (0, IDC_SIZEWE32A);
    infoPtr->hcurDivopen = LoadCursor32A (0, IDC_SIZENS32A);
    infoPtr->bPressed  = FALSE;
    infoPtr->bTracking = FALSE;
    infoPtr->iMoveItem = 0;
    infoPtr->himl = 0;
    infoPtr->iHotItem = -1;

    hdc = GetDC32 (0);
    hOldFont = SelectObject32 (hdc, GetStockObject32 (SYSTEM_FONT));
    GetTextMetrics32A (hdc, &tm);
    infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
    SelectObject32 (hdc, hOldFont);
    ReleaseDC32 (0, hdc);

    return 0;
}


static LRESULT
HEADER_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    HEADER_ITEM *lpItem;
    INT32 nItem;

    if (infoPtr->items) {
	lpItem = (HEADER_ITEM*)infoPtr->items;
        for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
	    if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACK32A))
		COMCTL32_Free (lpItem->pszText);
        }
        COMCTL32_Free (infoPtr->items);
    }

    if (infoPtr->himl)
	ImageList_Destroy (infoPtr->himl);

    COMCTL32_Free (infoPtr);

    return 0;
}


static __inline__ LRESULT
HEADER_GetFont (WND *wndPtr)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);

    return (LRESULT)infoPtr->hFont;
}


static LRESULT
HEADER_LButtonDblClk (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    POINT32 pt;
    UINT32  flags;
    INT32   nItem;

    pt.x = (INT32)LOWORD(lParam); 
    pt.y = (INT32)HIWORD(lParam);
    HEADER_InternalHitTest (wndPtr, &pt, &flags, &nItem);

    if ((wndPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER))
	HEADER_SendHeaderNotify (wndPtr, HDN_ITEMDBLCLICK32A, nItem);
    else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
	HEADER_SendHeaderNotify (wndPtr, HDN_DIVIDERDBLCLICK32A, nItem);

    return 0;
}


static LRESULT
HEADER_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    POINT32 pt;
    UINT32  flags;
    INT32   nItem;
    HDC32   hdc;

    pt.x = (INT32)LOWORD(lParam); 
    pt.y = (INT32)HIWORD(lParam);
    HEADER_InternalHitTest (wndPtr, &pt, &flags, &nItem);

    if ((wndPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
	SetCapture32 (wndPtr->hwndSelf);
	infoPtr->bCaptured = TRUE;   
	infoPtr->bPressed  = TRUE;
	infoPtr->iMoveItem = nItem;

	infoPtr->items[nItem].bDown = TRUE;

	/* Send WM_CUSTOMDRAW */
	hdc = GetDC32 (wndPtr->hwndSelf);
	HEADER_RefreshItem (wndPtr, hdc, nItem);
	ReleaseDC32 (wndPtr->hwndSelf, hdc);

	TRACE (header, "Pressed item %d!\n", nItem);
    } 
    else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
	if (!(HEADER_SendHeaderNotify (wndPtr, HDN_BEGINTRACK32A, nItem))) {
	    SetCapture32 (wndPtr->hwndSelf);
	    infoPtr->bCaptured = TRUE;   
	    infoPtr->bTracking = TRUE;
	    infoPtr->iMoveItem = nItem;
	    infoPtr->nOldWidth = infoPtr->items[nItem].cxy;
	    infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;

	    if (!(wndPtr->dwStyle & HDS_FULLDRAG)) {
		infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
		hdc = GetDC32 (wndPtr->hwndSelf);
		HEADER_DrawTrackLine (wndPtr, hdc, infoPtr->xOldTrack);
		ReleaseDC32 (wndPtr->hwndSelf, hdc);
	    }

	    TRACE (header, "Begin tracking item %d!\n", nItem);
	}
    }

    return 0;
}


static LRESULT
HEADER_LButtonUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    POINT32 pt;
    UINT32  flags;
    INT32   nItem, nWidth;
    HDC32   hdc;

    pt.x = (INT32)LOWORD(lParam);
    pt.y = (INT32)HIWORD(lParam);
    HEADER_InternalHitTest (wndPtr, &pt, &flags, &nItem);

    if (infoPtr->bPressed) {
	if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) {
	    infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
	    hdc = GetDC32 (wndPtr->hwndSelf);
	    HEADER_RefreshItem (wndPtr, hdc, infoPtr->iMoveItem);
	    ReleaseDC32 (wndPtr->hwndSelf, hdc);

	    HEADER_SendClickNotify (wndPtr, HDN_ITEMCLICK32A, infoPtr->iMoveItem);
	}
	TRACE (header, "Released item %d!\n", infoPtr->iMoveItem);
	infoPtr->bPressed = FALSE;
    }
    else if (infoPtr->bTracking) {
	TRACE (header, "End tracking item %d!\n", infoPtr->iMoveItem);
	infoPtr->bTracking = FALSE;

	HEADER_SendHeaderNotify (wndPtr, HDN_ENDTRACK32A, infoPtr->iMoveItem);

	if (!(wndPtr->dwStyle & HDS_FULLDRAG)) {
	    hdc = GetDC32 (wndPtr->hwndSelf);
	    HEADER_DrawTrackLine (wndPtr, hdc, infoPtr->xOldTrack);
	    ReleaseDC32 (wndPtr->hwndSelf, hdc);
	    if (HEADER_SendHeaderNotify (wndPtr, HDN_ITEMCHANGING32A, infoPtr->iMoveItem))
		infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth;
	    else {
		nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
		if (nWidth < 0)
		    nWidth = 0;
		infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
		HEADER_SendHeaderNotify (wndPtr, HDN_ITEMCHANGED32A, infoPtr->iMoveItem);
	    }

	    HEADER_SetItemBounds (wndPtr);
	    hdc = GetDC32 (wndPtr->hwndSelf);
	    HEADER_Refresh (wndPtr, hdc);
	    ReleaseDC32 (wndPtr->hwndSelf, hdc);
	}
    }

    if (infoPtr->bCaptured) {
	infoPtr->bCaptured = FALSE;
	ReleaseCapture ();
	HEADER_SendSimpleNotify (wndPtr, NM_RELEASEDCAPTURE);
    }

    return 0;
}


static LRESULT
HEADER_MouseMove (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    POINT32 pt;
    UINT32  flags;
    INT32   nItem, nWidth;
    HDC32   hdc;

    pt.x = (INT32)LOWORD(lParam);
    pt.y = (INT32)HIWORD(lParam);
    HEADER_InternalHitTest (wndPtr, &pt, &flags, &nItem);

    if ((wndPtr->dwStyle & HDS_BUTTONS) && (wndPtr->dwStyle & HDS_HOTTRACK)) {
	if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
	    infoPtr->iHotItem = nItem;
	else
	    infoPtr->iHotItem = -1;
	hdc = GetDC32 (wndPtr->hwndSelf);
	HEADER_Refresh (wndPtr, hdc);
	ReleaseDC32 (wndPtr->hwndSelf, hdc);
    }

    if (infoPtr->bCaptured) {
	if (infoPtr->bPressed) {
	    if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
		infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
	    else
		infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
	    hdc = GetDC32 (wndPtr->hwndSelf);
	    HEADER_RefreshItem (wndPtr, hdc, infoPtr->iMoveItem);
	    ReleaseDC32 (wndPtr->hwndSelf, hdc);

	    TRACE (header, "Moving pressed item %d!\n", infoPtr->iMoveItem);
	}
	else if (infoPtr->bTracking) {
	    if (wndPtr->dwStyle & HDS_FULLDRAG) {
		if (HEADER_SendHeaderNotify (wndPtr, HDN_ITEMCHANGING32A, infoPtr->iMoveItem))
		    infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth;
		else {
		    nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
		    if (nWidth < 0)
			nWidth = 0;
		    infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
		    HEADER_SendHeaderNotify (wndPtr, HDN_ITEMCHANGED32A,
					     infoPtr->iMoveItem);
		}
		HEADER_SetItemBounds (wndPtr);
		hdc = GetDC32 (wndPtr->hwndSelf);
		HEADER_Refresh (wndPtr, hdc);
		ReleaseDC32 (wndPtr->hwndSelf, hdc);
	    }
	    else {
		hdc = GetDC32 (wndPtr->hwndSelf);
		HEADER_DrawTrackLine (wndPtr, hdc, infoPtr->xOldTrack);
		infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
		if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
		    infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
		infoPtr->items[infoPtr->iMoveItem].cxy = 
		    infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
		HEADER_DrawTrackLine (wndPtr, hdc, infoPtr->xOldTrack);
		ReleaseDC32 (wndPtr->hwndSelf, hdc);
	    }

	    HEADER_SendHeaderNotify (wndPtr, HDN_TRACK32A, infoPtr->iMoveItem);
	    TRACE (header, "Tracking item %d!\n", infoPtr->iMoveItem);
	}
    }

    if ((wndPtr->dwStyle & HDS_BUTTONS) && (wndPtr->dwStyle & HDS_HOTTRACK)) {
	FIXME (header, "hot track support!\n");
    }

    return 0;
}


static LRESULT
HEADER_Paint (WND *wndPtr, WPARAM32 wParam)
{
    HDC32 hdc;
    PAINTSTRUCT32 ps;

    hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
    HEADER_Refresh (wndPtr, hdc);
    if(!wParam)
	EndPaint32 (wndPtr->hwndSelf, &ps);
    return 0;
}


static LRESULT
HEADER_RButtonUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    return HEADER_SendSimpleNotify (wndPtr, NM_RCLICK);
}


static LRESULT
HEADER_SetCursor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    POINT32 pt;
    UINT32  flags;
    INT32   nItem;

    TRACE (header, "code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));

    GetCursorPos32 (&pt);
    ScreenToClient32 (wndPtr->hwndSelf, &pt);

    HEADER_InternalHitTest (wndPtr, &pt, &flags, &nItem);

    if (flags == HHT_ONDIVIDER)
        SetCursor32 (infoPtr->hcurDivider);
    else if (flags == HHT_ONDIVOPEN)
        SetCursor32 (infoPtr->hcurDivopen);
    else
        SetCursor32 (infoPtr->hcurArrow);

    return 0;
}


static LRESULT
HEADER_SetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(wndPtr);
    TEXTMETRIC32A tm;
    HFONT32 hFont, hOldFont;
    HDC32 hdc;

    infoPtr->hFont = (HFONT32)wParam;

    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);

    hdc = GetDC32 (0);
    hOldFont = SelectObject32 (hdc, hFont);
    GetTextMetrics32A (hdc, &tm);
    infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
    SelectObject32 (hdc, hOldFont);
    ReleaseDC32 (0, hdc);

    if (lParam) {
        HEADER_ForceItemBounds (wndPtr, infoPtr->nHeight);
        hdc = GetDC32 (wndPtr->hwndSelf);
        HEADER_Refresh (wndPtr, hdc);
        ReleaseDC32 (wndPtr->hwndSelf, hdc);
    }

    return 0;
}


LRESULT WINAPI
HEADER_WindowProc (HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
{
    WND *wndPtr = WIN_FindWndPtr(hwnd);

    switch (msg) {
	case HDM_CREATEDRAGIMAGE:
	    return HEADER_CreateDragImage (wndPtr, wParam);

	case HDM_DELETEITEM:
	    return HEADER_DeleteItem (wndPtr, wParam);

	case HDM_GETIMAGELIST:
	    return HEADER_GetImageList (wndPtr);

	case HDM_GETITEM32A:
	    return HEADER_GetItem32A (wndPtr, wParam, lParam);

//	case HDM_GETITEM32W:

	case HDM_GETITEMCOUNT:
	    return HEADER_GetItemCount (wndPtr);

	case HDM_GETITEMRECT:
	    return HEADER_GetItemRect (wndPtr, wParam, lParam);

//	case HDM_GETORDERARRAY:
//	case HDM_GETUNICODEFORMAT:

	case HDM_HITTEST:
	    return HEADER_HitTest (wndPtr, wParam, lParam);

	case HDM_INSERTITEM32A:
	    return HEADER_InsertItem32A (wndPtr, wParam, lParam);

//	case HDM_INSERTITEM32W:

	case HDM_LAYOUT:
	    return HEADER_Layout (wndPtr, wParam, lParam);

	case HDM_SETIMAGELIST:
	    return HEADER_SetImageList (wndPtr, wParam, lParam);

	case HDM_SETITEM32A:
	    return HEADER_SetItem32A (wndPtr, wParam, lParam);

//	case HDM_SETITEM32W:
//	case HDM_SETORDERARRAY:
//	case HDM_SETUNICODEFORMAT:


        case WM_CREATE:
            return HEADER_Create (wndPtr, wParam, lParam);

        case WM_DESTROY:
            return HEADER_Destroy (wndPtr, wParam, lParam);

        case WM_ERASEBKGND:
            return 1;

        case WM_GETDLGCODE:
            return DLGC_WANTTAB | DLGC_WANTARROWS;

        case WM_GETFONT:
            return HEADER_GetFont (wndPtr);

        case WM_LBUTTONDBLCLK:
            return HEADER_LButtonDblClk (wndPtr, wParam, lParam);

        case WM_LBUTTONDOWN:
            return HEADER_LButtonDown (wndPtr, wParam, lParam);

        case WM_LBUTTONUP:
            return HEADER_LButtonUp (wndPtr, wParam, lParam);

        case WM_MOUSEMOVE:
            return HEADER_MouseMove (wndPtr, wParam, lParam);

        case WM_PAINT:
            return HEADER_Paint (wndPtr, wParam);

        case WM_RBUTTONUP:
            return HEADER_RButtonUp (wndPtr, wParam, lParam);

        case WM_SETCURSOR:
            return HEADER_SetCursor (wndPtr, wParam, lParam);

        case WM_SETFONT:
            return HEADER_SetFont (wndPtr, wParam, lParam);

        default:
            if (msg >= WM_USER) 
		ERR (header, "unknown msg %04x wp=%04x lp=%08lx\n",
		     msg, wParam, lParam );
	    return DefWindowProc32A (hwnd, msg, wParam, lParam);
    }
    return 0;
}


VOID
HEADER_Register (VOID)
{
    WNDCLASS32A wndClass;

    if (GlobalFindAtom32A (WC_HEADER32A)) return;

    ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
    wndClass.lpfnWndProc   = (WNDPROC32)HEADER_WindowProc;
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
    wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
    wndClass.lpszClassName = WC_HEADER32A;
 
    RegisterClass32A (&wndClass);
}


VOID
HEADER_Unregister (VOID)
{
    if (GlobalFindAtom32A (WC_HEADER32A))
	UnregisterClass32A (WC_HEADER32A, (HINSTANCE32)NULL);
}

wine-981025/dlls/comctl32/hotkey.c100644    771    771       16073  6614330267  16542 0ustar  julliardjulliard/*
 * Hotkey control
 *
 * Copyright 1998 Eric Kohl
 *
 * NOTES
 *   Development in progress. An author is needed! Any volunteers?
 *   I will only improve this control once in a while.
 *     Eric <ekohl@abo.rhein-zeitung.de>
 *
 * TODO:
 *   - Some messages.
 *   - Display code.
 */

#include "windows.h"
#include "commctrl.h"
#include "hotkey.h"
#include "win.h"
#include "debug.h"


#define HOTKEY_GetInfoPtr(wndPtr) ((HOTKEY_INFO *)wndPtr->wExtra[0])


// << HOTHEY_GetHotKey >>
// << HOTHEY_SetHotKey >>
// << HOTHEY_SetRules >>



// << HOTKEY_Char >>


static LRESULT
HOTKEY_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr;
    TEXTMETRIC32A tm;
    HDC32 hdc;

    /* allocate memory for info structure */
    infoPtr = (HOTKEY_INFO *)COMCTL32_Alloc (sizeof(HOTKEY_INFO));
    wndPtr->wExtra[0] = (DWORD)infoPtr;

    if (infoPtr == NULL) {
	ERR (listview, "could not allocate info memory!\n");
	return 0;
    }

    if ((HOTKEY_INFO*)wndPtr->wExtra[0] != infoPtr) {
	ERR (listview, "pointer assignment error!\n");
	return 0;
    }


    /* initialize info structure */

    /* get default font height */
    hdc = GetDC32 (wndPtr->hwndSelf);
    GetTextMetrics32A (hdc, &tm);
    infoPtr->nHeight = tm.tmHeight;
    ReleaseDC32 (wndPtr->hwndSelf, hdc);

    return 0;
}


static LRESULT
HOTKEY_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);



    /* free hotkey info data */
    COMCTL32_Free (infoPtr);

    return 0;
}


static LRESULT
HOTKEY_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);
    HBRUSH32 hBrush;
    RECT32   rc;

    hBrush =
	(HBRUSH32)SendMessage32A (wndPtr->parent->hwndSelf, WM_CTLCOLOREDIT,
				  wParam, (LPARAM)wndPtr->hwndSelf);
    if (hBrush)
	hBrush = (HBRUSH32)GetStockObject32 (WHITE_BRUSH);
    GetClientRect32 (wndPtr->hwndSelf, &rc);

    FillRect32 ((HDC32)wParam, &rc, hBrush);

    return -1;
}


__inline__ static LRESULT
HOTKEY_GetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    return infoPtr->hFont;
}


static LRESULT
HOTKEY_KeyDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    switch (wParam) {
	case VK_RETURN:
	case VK_TAB:
	case VK_SPACE:
	case VK_DELETE:
	case VK_ESCAPE:
	case VK_BACK:
	    return DefWindowProc32A (wndPtr->hwndSelf, WM_KEYDOWN, wParam, lParam);

	case VK_SHIFT:
	case VK_CONTROL:
	case VK_MENU:
	    FIXME (hotkey, "modifier key pressed!\n");
	    break;

	default:
	    FIXME (hotkey, " %d\n", wParam);
	    break;
    }

    return TRUE;
}


static LRESULT
HOTKEY_KeyUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    FIXME (hotkey, " %d\n", wParam);

    return 0;
}


static LRESULT
HOTKEY_KillFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    infoPtr->bFocus = FALSE;
    DestroyCaret32 ();

    return 0;
}


static LRESULT
HOTKEY_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
//    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    SetFocus32 (wndPtr->hwndSelf);

    return 0;
}


__inline__ static LRESULT
HOTKEY_NCCreate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    wndPtr->dwExStyle |= WS_EX_CLIENTEDGE;

    return DefWindowProc32A (wndPtr->hwndSelf, WM_NCCREATE, wParam, lParam);
}





static LRESULT
HOTKEY_SetFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    infoPtr->bFocus = TRUE;


    CreateCaret32 (wndPtr->hwndSelf, (HBITMAP32)0, 1, infoPtr->nHeight);

    SetCaretPos32 (1, 1);

    ShowCaret32 (wndPtr->hwndSelf);


    return 0;
}


__inline__ static LRESULT
HOTKEY_SetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);
    TEXTMETRIC32A tm;
    HDC32 hdc;
    HFONT32 hOldFont = 0;

    infoPtr->hFont = (HFONT32)wParam;

    hdc = GetDC32 (wndPtr->hwndSelf);
    if (infoPtr->hFont)
	hOldFont = SelectObject32 (hdc, infoPtr->hFont);

    GetTextMetrics32A (hdc, &tm);
    infoPtr->nHeight = tm.tmHeight;

    if (infoPtr->hFont)
	SelectObject32 (hdc, hOldFont);
    ReleaseDC32 (wndPtr->hwndSelf, hdc);

    if (LOWORD(lParam)) {

	FIXME (hotkey, "force redraw!\n");

    }

    return 0;
}


static LRESULT
HOTKEY_SysKeyDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    switch (wParam) {
	case VK_RETURN:
	case VK_TAB:
	case VK_SPACE:
	case VK_DELETE:
	case VK_ESCAPE:
	case VK_BACK:
	    return DefWindowProc32A (wndPtr->hwndSelf, WM_SYSKEYDOWN, wParam, lParam);

	case VK_SHIFT:
	case VK_CONTROL:
	case VK_MENU:
	    FIXME (hotkey, "modifier key pressed!\n");
	    break;

	default:
	    FIXME (hotkey, " %d\n", wParam);
	    break;
    }

    return TRUE;
}


static LRESULT
HOTKEY_SysKeyUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr(wndPtr);

    FIXME (hotkey, " %d\n", wParam);

    return 0;
}



LRESULT WINAPI
HOTKEY_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
{
    WND *wndPtr = WIN_FindWndPtr(hwnd);

    switch (uMsg)
    {
//	case HKM_GETHOTKEY:
//	case HKM_SETHOTKEY:
//	case HKM_SETRULES:

//	case WM_CHAR:

	case WM_CREATE:
	    return HOTKEY_Create (wndPtr, wParam, lParam);

	case WM_DESTROY:
	    return HOTKEY_Destroy (wndPtr, wParam, lParam);

	case WM_ERASEBKGND:
	    return HOTKEY_EraseBackground (wndPtr, wParam, lParam);

	case WM_GETDLGCODE:
	    return DLGC_WANTCHARS | DLGC_WANTARROWS;

	case WM_GETFONT:
	    return HOTKEY_GetFont (wndPtr, wParam, lParam);

	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
	    return HOTKEY_KeyDown (wndPtr, wParam, lParam);

	case WM_KEYUP:
	case WM_SYSKEYUP:
	    return HOTKEY_KeyUp (wndPtr, wParam, lParam);

	case WM_KILLFOCUS:
	    return HOTKEY_KillFocus (wndPtr, wParam, lParam);

	case WM_LBUTTONDOWN:
	    return HOTKEY_LButtonDown (wndPtr, wParam, lParam);

	case WM_NCCREATE:
	    return HOTKEY_NCCreate (wndPtr, wParam, lParam);

//	case WM_PAINT:

	case WM_SETFOCUS:
	    return HOTKEY_SetFocus (wndPtr, wParam, lParam);

	case WM_SETFONT:
	    return HOTKEY_SetFont (wndPtr, wParam, lParam);

//	case WM_SYSCHAR:

	default:
	    if (uMsg >= WM_USER)
		ERR (hotkey, "unknown msg %04x wp=%08x lp=%08lx\n",
		     uMsg, wParam, lParam);
	    return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
    }
    return 0;
}


VOID
HOTKEY_Register (VOID)
{
    WNDCLASS32A wndClass;

    if (GlobalFindAtom32A (HOTKEY_CLASS32A)) return;

    ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
    wndClass.style         = CS_GLOBALCLASS;
    wndClass.lpfnWndProc   = (WNDPROC32)HOTKEY_WindowProc;
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(HOTKEY_INFO *);
    wndClass.hCursor       = 0;
    wndClass.hbrBackground = 0;
    wndClass.lpszClassName = HOTKEY_CLASS32A;
 
    RegisterClass32A (&wndClass);
}


VOID
HOTKEY_Unregister (VOID)
{
    if (GlobalFindAtom32A (HOTKEY_CLASS32A))
	UnregisterClass32A (HOTKEY_CLASS32A, (HINSTANCE32)NULL);
}