⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comboex.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * ComboBoxEx control
 *
 * Copyright 1998, 1999 Eric Kohl
 * Copyright 2000, 2001, 2002 Guy Albertelli <galberte@neo.lrun.com>
 * Copyright 2002 Dimitrie O. Paun
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * NOTE
 * 
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun.
 * 
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
 * 
 */

#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
#include "comctl32.h"
#include "wine/debug.h"
#include "wine/unicode.h"

WINE_DEFAULT_DEBUG_CHANNEL(comboex);

/* Item structure */
typedef struct _CBE_ITEMDATA
{
    struct _CBE_ITEMDATA *next;
    UINT         mask;
    LPWSTR       pszText;
    LPWSTR       pszTemp;
    int          cchTextMax;
    int          iImage;
    int          iSelectedImage;
    int          iOverlay;
    int          iIndent;
    LPARAM       lParam;
} CBE_ITEMDATA;

/* ComboBoxEx structure */
typedef struct
{
    HIMAGELIST   himl;
    HWND         hwndSelf;         /* my own hwnd */
    HWND         hwndNotify;       /* my parent hwnd */
    HWND         hwndCombo;
    HWND         hwndEdit;
    WNDPROC      prevEditWndProc;  /* previous Edit WNDPROC value */
    WNDPROC      prevComboWndProc; /* previous Combo WNDPROC value */
    DWORD        dwExtStyle;
    INT          selected;         /* index of selected item */
    DWORD        flags;            /* WINE internal flags */
    HFONT        defaultFont;
    HFONT        font;
    INT          nb_items;         /* Number of items */
    BOOL         unicode;          /* TRUE if this window is Unicode   */
    BOOL         NtfUnicode;       /* TRUE if parent wants notify in Unicode */
    CBE_ITEMDATA *edit;            /* item data for edit item */
    CBE_ITEMDATA *items;           /* Array of items */
} COMBOEX_INFO;

/* internal flags in the COMBOEX_INFO structure */
#define  WCBE_ACTEDIT		0x00000001  /* Edit active i.e.
                                             * CBEN_BEGINEDIT issued
                                             * but CBEN_ENDEDIT{A|W}
                                             * not yet issued. */
#define  WCBE_EDITCHG		0x00000002  /* Edit issued EN_CHANGE */
#define  WCBE_EDITHASCHANGED	(WCBE_ACTEDIT | WCBE_EDITCHG)
#define  WCBE_EDITFOCUSED	0x00000004  /* Edit control has focus */
#define  WCBE_MOUSECAPTURED	0x00000008  /* Combo has captured mouse */
#define  WCBE_MOUSEDRAGGED      0x00000010  /* User has dragged in combo */

#define ID_CB_EDIT		1001


/*
 * Special flag set in DRAWITEMSTRUCT itemState field. It is set by
 * the ComboEx version of the Combo Window Proc so that when the
 * WM_DRAWITEM message is then passed to ComboEx, we know that this
 * particular WM_DRAWITEM message is for listbox only items. Any messasges
 * without this flag is then for the Edit control field.
 *
 * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that
 * only version 4.0 applications will have ODS_COMBOBOXEDIT set.
 */
#define ODS_COMBOEXLBOX		0x4000



/* Height in pixels of control over the amount of the selected font */
#define CBE_EXTRA		3

/* Indent amount per MS documentation */
#define CBE_INDENT		10

/* Offset in pixels from left side for start of image or text */
#define CBE_STARTOFFSET		6

/* Offset between image and text */
#define CBE_SEP			4

static const WCHAR COMBOEX_SUBCLASS_PROP[] = {
    'C','C','C','o','m','b','o','E','x','3','2',
    'S','u','b','c','l','a','s','s','I','n','f','o',0
};

#define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0))


/* Things common to the entire DLL */
static LRESULT WINAPI COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT WINAPI COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr);
typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR);

inline static BOOL is_textW(LPCWSTR str)
{
    return str && str != LPSTR_TEXTCALLBACKW;
}

inline static BOOL is_textA(LPCSTR str)
{
    return str && str != LPSTR_TEXTCALLBACKA;
}

inline static LPCSTR debugstr_txt(LPCWSTR str)
{
    if (str == LPSTR_TEXTCALLBACKW) return "(callback)";
    return debugstr_w(str);
}

static void COMBOEX_DumpItem (CBE_ITEMDATA *item)
{
    TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n",
          item, item->mask, item->pszText, item->cchTextMax, item->iImage);
    TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
          item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam);
    if (item->mask & CBEIF_TEXT)
        TRACE("item %p - pszText=%s\n", item, debugstr_txt(item->pszText));
}


static void COMBOEX_DumpInput (COMBOBOXEXITEMW *input)
{
    TRACE("input - mask=%08x, iItem=%d, pszText=%p, cchTM=%d, iImage=%d\n",
          input->mask, input->iItem, input->pszText, input->cchTextMax,
          input->iImage);
    if (input->mask & CBEIF_TEXT)
        TRACE("input - pszText=<%s>\n", debugstr_txt(input->pszText));
    TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
          input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam);
}


inline static CBE_ITEMDATA *get_item_data(COMBOEX_INFO *infoPtr, INT index)
{
    return (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, CB_GETITEMDATA,
		                         (WPARAM)index, 0);
}

inline static cmp_func_t get_cmp_func(COMBOEX_INFO *infoPtr)
{
    return infoPtr->dwExtStyle & CBES_EX_CASESENSITIVE ? lstrcmpW : lstrcmpiW;
}

static INT COMBOEX_Notify (COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr)
{
    hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
    hdr->hwndFrom = infoPtr->hwndSelf;
    hdr->code = code;
    if (infoPtr->NtfUnicode)
	return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr);
    else
	return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr);
}


static INT
COMBOEX_NotifyItem (COMBOEX_INFO *infoPtr, INT code, NMCOMBOBOXEXW *hdr)
{
    /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
    if (infoPtr->NtfUnicode)
	return COMBOEX_Notify (infoPtr, code, &hdr->hdr);
    else {
	LPWSTR wstr = hdr->ceItem.pszText;
	LPSTR astr = 0;
	INT ret, len = 0;

	if ((hdr->ceItem.mask & CBEIF_TEXT) && is_textW(wstr)) {
	    len = WideCharToMultiByte (CP_ACP, 0, wstr, -1, 0, 0, NULL, NULL);
	    if (len > 0) {
		astr = (LPSTR)Alloc ((len + 1)*sizeof(CHAR));
		if (!astr) return 0;
		WideCharToMultiByte (CP_ACP, 0, wstr, -1, astr, len, 0, 0);
		hdr->ceItem.pszText = (LPWSTR)astr;
	    }
	}

	if (code == CBEN_ENDEDITW) code = CBEN_ENDEDITA;
	else if (code == CBEN_GETDISPINFOW) code = CBEN_GETDISPINFOA;
	else if (code == CBEN_DRAGBEGINW) code = CBEN_DRAGBEGINA;

	ret = COMBOEX_Notify (infoPtr, code, (NMHDR *)hdr);

	if (astr && hdr->ceItem.pszText == (LPWSTR)astr)
	    hdr->ceItem.pszText = wstr;

	if (astr) Free(astr);

	return ret;
    }
}


static INT COMBOEX_NotifyEndEdit (COMBOEX_INFO *infoPtr, NMCBEENDEDITW *neew, LPCWSTR wstr)
{
    /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
    if (infoPtr->NtfUnicode) {
	lstrcpynW(neew->szText, wstr, CBEMAXSTRLEN);
	return COMBOEX_Notify (infoPtr, CBEN_ENDEDITW, &neew->hdr);
    } else {
	NMCBEENDEDITA neea;

        memcpy (&neea.hdr, &neew->hdr, sizeof(NMHDR));
        neea.fChanged = neew->fChanged;
        neea.iNewSelection = neew->iNewSelection;
        WideCharToMultiByte (CP_ACP, 0, wstr, -1, neea.szText, CBEMAXSTRLEN, 0, 0);
        neea.iWhy = neew->iWhy;

        return COMBOEX_Notify (infoPtr, CBEN_ENDEDITA, &neea.hdr);
    }
}


static void COMBOEX_NotifyDragBegin(COMBOEX_INFO *infoPtr, LPCWSTR wstr)
{
    /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */
    if (infoPtr->NtfUnicode) {
        NMCBEDRAGBEGINW ndbw;

	ndbw.iItemid = -1;
	lstrcpynW(ndbw.szText, wstr, CBEMAXSTRLEN);
	COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINW, &ndbw.hdr);
    } else {
	NMCBEDRAGBEGINA ndba;

	ndba.iItemid = -1;
	WideCharToMultiByte (CP_ACP, 0, wstr, -1, ndba.szText, CBEMAXSTRLEN, 0, 0);

	COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINA, &ndba.hdr);
    }
}


static void COMBOEX_FreeText (CBE_ITEMDATA *item)
{
    if (is_textW(item->pszText)) Free(item->pszText);
    item->pszText = 0;
    if (item->pszTemp) Free(item->pszTemp);
    item->pszTemp = 0;
}


static INT COMBOEX_GetIndex(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
{
    CBE_ITEMDATA *moving;
    INT index;
    
    moving = infoPtr->items;
    index = infoPtr->nb_items - 1;

    while (moving && (moving != item)) {
        moving = moving->next;
        index--;
    }
    if (!moving || (index < 0)) {
        ERR("COMBOBOXEX item structures broken. Please report!\n");
        return -1;
    }
    return index;
}


static LPCWSTR COMBOEX_GetText(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
{
    NMCOMBOBOXEXW nmce;
    LPWSTR text, buf;
    INT len;

    if (item->pszText != LPSTR_TEXTCALLBACKW)
	return item->pszText;

    ZeroMemory(&nmce, sizeof(nmce));
    nmce.ceItem.mask = CBEIF_TEXT;
    nmce.ceItem.lParam = item->lParam;
    nmce.ceItem.iItem = COMBOEX_GetIndex(infoPtr, item);
    COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce);

    if (is_textW(nmce.ceItem.pszText)) {
	len = MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, NULL, 0);
	buf = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR));
	if (buf)
	    MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, buf, len);
	if (nmce.ceItem.mask & CBEIF_DI_SETITEM) {
	    COMBOEX_FreeText(item);
	    item->pszText = buf;
	} else {
	    if (item->pszTemp) Free(item->pszTemp);
	    item->pszTemp = buf;
	}
	text = buf;
    } else
	text = nmce.ceItem.pszText;

    if (nmce.ceItem.mask & CBEIF_DI_SETITEM)
	item->pszText = text;
    return text;
}


static void COMBOEX_GetComboFontSize (COMBOEX_INFO *infoPtr, SIZE *size)
{
    static const WCHAR strA[] = { 'A', 0 };
    HFONT nfont, ofont;
    HDC mydc;

    mydc = GetDC (0); /* why the entire screen???? */
    nfont = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
    ofont = (HFONT) SelectObject (mydc, nfont);
    GetTextExtentPointW (mydc, strA, 1, size);
    SelectObject (mydc, ofont);
    ReleaseDC (0, mydc);
    TRACE("selected font hwnd=%p, height=%d\n", nfont, size->cy);
}


static void COMBOEX_CopyItem (CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit)
{
    if (cit->mask & CBEIF_TEXT) {
        /*
         * when given a text buffer actually use that buffer
         */
        if (cit->pszText) {
	    if (is_textW(item->pszText))
                lstrcpynW(cit->pszText, item->pszText, cit->cchTextMax);
	    else
		cit->pszText[0] = 0;
        } else {
            cit->pszText        = item->pszText;
            cit->cchTextMax     = item->cchTextMax;
        }
    }
    if (cit->mask & CBEIF_IMAGE)
	cit->iImage         = item->iImage;
    if (cit->mask & CBEIF_SELECTEDIMAGE)
	cit->iSelectedImage = item->iSelectedImage;
    if (cit->mask & CBEIF_OVERLAY)
	cit->iOverlay       = item->iOverlay;
    if (cit->mask & CBEIF_INDENT)
	cit->iIndent        = item->iIndent;
    if (cit->mask & CBEIF_LPARAM)
	cit->lParam         = item->lParam;
}


static void COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr)
{
    SIZE mysize;
    INT x, y, w, h, xioff;
    RECT rect;

    if (!infoPtr->hwndEdit) return;

    if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) {
    	IMAGEINFO iinfo;
        iinfo.rcImage.left = iinfo.rcImage.right = 0;
	ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
	xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP;
    }  else xioff = 0;

    GetClientRect (infoPtr->hwndCombo, &rect);
    InflateRect (&rect, -2, -2);
    InvalidateRect (infoPtr->hwndCombo, &rect, TRUE);

    /* reposition the Edit control based on whether icon exists */
    COMBOEX_GetComboFontSize (infoPtr, &mysize);
    TRACE("Combo font x=%d, y=%d\n", mysize.cx, mysize.cy);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -