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

📄 comboex.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
    if ((cit->mask & CBEIF_TEXT) && is_textA(cit->pszText)) {
	INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0);
	wstr = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR));
	if (!wstr) return FALSE;
	MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len);
	citW.pszText = wstr;
    }
    ret = COMBOEX_SetItemW(infoPtr, &citW);

    if (wstr) Free(wstr);

    return ret;
}


static BOOL COMBOEX_SetUnicodeFormat (COMBOEX_INFO *infoPtr, BOOL value)
{
    BOOL bTemp = infoPtr->unicode;

    TRACE("to %s, was %s\n", value ? "TRUE":"FALSE", bTemp ? "TRUE":"FALSE");

    infoPtr->unicode = value;

    return bTemp;
}


/* ***  CB_xxx message support  *** */

static INT
COMBOEX_FindStringExact (COMBOEX_INFO *infoPtr, INT start, LPCWSTR str)
{
    INT i;
    cmp_func_t cmptext = get_cmp_func(infoPtr);
    INT count = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0);

    /* now search from after starting loc and wrapping back to start */
    for(i=start+1; i<count; i++) {
	CBE_ITEMDATA *item = get_item_data(infoPtr, i);
	if (cmptext(COMBOEX_GetText(infoPtr, item), str) == 0) return i;
    }
    for(i=0; i<=start; i++) {
	CBE_ITEMDATA *item = get_item_data(infoPtr, i);
	if (cmptext(COMBOEX_GetText(infoPtr, item), str) == 0) return i;
    }
    return CB_ERR;
}


static DWORD_PTR COMBOEX_GetItemData (COMBOEX_INFO *infoPtr, INT index)
{
    CBE_ITEMDATA *item1, *item2;
    DWORD_PTR ret = 0;

    item1 = get_item_data(infoPtr, index);
    if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
	item2 = COMBOEX_FindItem (infoPtr, index);
	if (item2 != item1) {
	    ERR("data structures damaged!\n");
	    return CB_ERR;
	}
	if (item1->mask & CBEIF_LPARAM) ret = item1->lParam;
	TRACE("returning 0x%08lx\n", ret);
    } else {
        ret = (DWORD_PTR)item1;
        TRACE("non-valid result from combo, returning 0x%08lx\n", ret);
    }
    return ret;
}


static INT COMBOEX_SetCursel (COMBOEX_INFO *infoPtr, INT index)
{
    CBE_ITEMDATA *item;
    INT sel;

    if (!(item = COMBOEX_FindItem(infoPtr, index)))
	return SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0);

    TRACE("selecting item %d text=%s\n", index, debugstr_txt(item->pszText));
    infoPtr->selected = index;

    sel = (INT)SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0);
    COMBOEX_SetEditText (infoPtr, item);
    return sel;
}


static DWORD_PTR COMBOEX_SetItemData (COMBOEX_INFO *infoPtr, INT index, DWORD_PTR data)
{
    CBE_ITEMDATA *item1, *item2;

    item1 = get_item_data(infoPtr, index);
    if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) {
	item2 = COMBOEX_FindItem (infoPtr, index);
	if (item2 != item1) {
	    ERR("data structures damaged!\n");
	    return CB_ERR;
	}
	item1->mask |= CBEIF_LPARAM;
	item1->lParam = data;
	TRACE("setting lparam to 0x%08lx\n", data);
	return 0;
    }
    TRACE("non-valid result from combo %p\n", item1);
    return (DWORD_PTR)item1;
}


static INT COMBOEX_SetItemHeight (COMBOEX_INFO *infoPtr, INT index, UINT height)
{
    RECT cb_wrect, cbx_wrect, cbx_crect;

    /* First, lets forward the message to the normal combo control
       just like Windows.     */
    if (infoPtr->hwndCombo)
       if (SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT,
			 index, height) == CB_ERR) return CB_ERR;

    GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
    GetWindowRect (infoPtr->hwndSelf, &cbx_wrect);
    GetClientRect (infoPtr->hwndSelf, &cbx_crect);
    /* the height of comboex as height of the combo + comboex border */
    height = cb_wrect.bottom-cb_wrect.top
             + cbx_wrect.bottom-cbx_wrect.top
             - (cbx_crect.bottom-cbx_crect.top);
    TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
	  cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
	  cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
    TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
	  cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
	  cbx_wrect.right-cbx_wrect.left, height);
    SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0,
		  cbx_wrect.right-cbx_wrect.left, height,
		  SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);

    return 0;
}


/* ***  WM_xxx message support  *** */


static LRESULT COMBOEX_Create (HWND hwnd, LPCREATESTRUCTA cs)
{
    static const WCHAR COMBOBOX[] = { 'C', 'o', 'm', 'b', 'o', 'B', 'o', 'x', 0 };
    static const WCHAR EDIT[] = { 'E', 'D', 'I', 'T', 0 };
    static const WCHAR NIL[] = { 0 };
    COMBOEX_INFO *infoPtr;
    LOGFONTW mylogfont;
    RECT wnrc1, clrc1, cmbwrc;
    INT i;

    /* allocate memory for info structure */
    infoPtr = (COMBOEX_INFO *)Alloc (sizeof(COMBOEX_INFO));
    if (!infoPtr) return -1;

    /* initialize info structure */
    /* note that infoPtr is allocated zero-filled */

    infoPtr->hwndSelf = hwnd;
    infoPtr->selected = -1;

    infoPtr->unicode = IsWindowUnicode (hwnd);
    infoPtr->hwndNotify = cs->hwndParent;

    i = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
    if ((i != NFR_ANSI) && (i != NFR_UNICODE)) {
	WARN("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
	i = NFR_ANSI;
    }
    infoPtr->NtfUnicode = (i == NFR_UNICODE);

    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);

    /* create combo box */
    GetWindowRect(hwnd, &wnrc1);
    GetClientRect(hwnd, &clrc1);
    TRACE("EX window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d)\n",
	  wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
	  clrc1.left, clrc1.top, clrc1.right, clrc1.bottom);

    /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
    /* specified. It then creates it's own version of the EDIT control  */
    /* and makes the ComboBox the parent. This is because a normal      */
    /* DROPDOWNLIST does not have an EDIT control, but we need one.     */
    /* We also need to place the edit control at the proper location    */
    /* (allow space for the icons).                                     */

    infoPtr->hwndCombo = CreateWindowW (COMBOBOX, NIL,
			 /* following line added to match native */
                         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
                         CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
			 /* was base and is necessary */
			 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED |
			 GetWindowLongW (hwnd, GWL_STYLE),
			 cs->y, cs->x, cs->cx, cs->cy, hwnd,
			 (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID),
			 (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL);

    /*
     * native does the following at this point according to trace:
     *  GetWindowThreadProcessId(hwndCombo,0)
     *  GetCurrentThreadId()
     *  GetWindowThreadProcessId(hwndCombo, &???)
     *  GetCurrentProcessId()
     */

    /*
     * Setup a property to hold the pointer to the COMBOBOXEX
     * data structure.
     */
    SetPropW(infoPtr->hwndCombo, COMBOEX_SUBCLASS_PROP, hwnd);
    infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndCombo,
	                        GWLP_WNDPROC, (DWORD_PTR)COMBOEX_ComboWndProc);
    infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);


    /*
     * Now create our own EDIT control so we can position it.
     * It is created only for CBS_DROPDOWN style
     */
    if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) {
	infoPtr->hwndEdit = CreateWindowExW (0, EDIT, NIL,
		    WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
		    0, 0, 0, 0,  /* will set later */
		    infoPtr->hwndCombo,
		    (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID),
		    (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL);

	/* native does the following at this point according to trace:
	 *  GetWindowThreadProcessId(hwndEdit,0)
	 *  GetCurrentThreadId()
	 *  GetWindowThreadProcessId(hwndEdit, &???)
	 *  GetCurrentProcessId()
	 */

	/*
	 * Setup a property to hold the pointer to the COMBOBOXEX
	 * data structure.
	 */
        SetPropW(infoPtr->hwndEdit, COMBOEX_SUBCLASS_PROP, hwnd);
	infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndEdit,
				 GWLP_WNDPROC, (DWORD_PTR)COMBOEX_EditWndProc);
	infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0);
    }

    /*
     * Locate the default font if necessary and then set it in
     * all associated controls
     */
    if (!infoPtr->font) {
	SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof(mylogfont),
			       &mylogfont, 0);
	infoPtr->font = infoPtr->defaultFont = CreateFontIndirectW (&mylogfont);
    }
    SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0);
    if (infoPtr->hwndEdit) {
	SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0);
	SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0);
    }

    COMBOEX_ReSize (infoPtr);

    /* Above is fairly certain, below is much less certain. */

    GetWindowRect(hwnd, &wnrc1);
    GetClientRect(hwnd, &clrc1);
    GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
    TRACE("EX window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d) CB wnd=(%d,%d)-(%d,%d)\n",
	  wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
	  clrc1.left, clrc1.top, clrc1.right, clrc1.bottom,
	  cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
    SetWindowPos(infoPtr->hwndCombo, HWND_TOP,
		 0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top,
		 SWP_NOACTIVATE | SWP_NOREDRAW);

    GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
    TRACE("CB window=(%d,%d)-(%d,%d)\n",
	  cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
    SetWindowPos(hwnd, HWND_TOP,
		 0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top,
		 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);

    COMBOEX_AdjustEditPos (infoPtr);

    /*
     * Create an item structure to represent the data in the
     * EDIT control. It is allocated zero-filled.
     */
    infoPtr->edit = (CBE_ITEMDATA *)Alloc (sizeof (CBE_ITEMDATA));
    if (!infoPtr->edit) {
	COMBOEX_Destroy(infoPtr);
	return -1;
    }

    return 0;
}


static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
    LRESULT lret;
    INT command = HIWORD(wParam);
    CBE_ITEMDATA *item = 0;
    WCHAR wintext[520];
    INT cursel, n, oldItem;
    NMCBEENDEDITW cbeend;
    DWORD oldflags;
    HWND parent = infoPtr->hwndNotify;

    TRACE("for command %d\n", command);

    switch (command)
    {
    case CBN_DROPDOWN:
	SetFocus (infoPtr->hwndCombo);
	ShowWindow (infoPtr->hwndEdit, SW_HIDE);
	return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);

    case CBN_CLOSEUP:
	SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
	/*
	 * from native trace of first dropdown after typing in URL in IE4
	 *  CB_GETCURSEL(Combo)
	 *  GetWindowText(Edit)
	 *  CB_GETCURSEL(Combo)
	 *  CB_GETCOUNT(Combo)
	 *  CB_GETITEMDATA(Combo, n)
	 *  WM_NOTIFY(parent, CBEN_ENDEDITA|W)
	 *  CB_GETCURSEL(Combo)
	 *  CB_SETCURSEL(COMBOEX, n)
	 *  SetFocus(Combo)
	 * the rest is supposition
	 */
	ShowWindow (infoPtr->hwndEdit, SW_SHOW);
	InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
	InvalidateRect (infoPtr->hwndEdit, 0, TRUE);
	cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
	if (cursel == -1) {
            cmp_func_t cmptext = get_cmp_func(infoPtr);
	    /* find match from edit against those in Combobox */
	    GetWindowTextW (infoPtr->hwndEdit, wintext, 520);
	    n = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0);
	    for (cursel = 0; cursel < n; cursel++){
                item = get_item_data(infoPtr, cursel);
		if ((INT_PTR)item == CB_ERR) break;
		if (!cmptext(COMBOEX_GetText(infoPtr, item), wintext)) break;
	    }
	    if ((cursel == n) || ((INT_PTR)item == CB_ERR)) {
		TRACE("failed to find match??? item=%p cursel=%d\n",
		      item, cursel);
		if (infoPtr->hwndEdit)
		    SetFocus(infoPtr->hwndEdit);
		return 0;
	    }
	}
	else {
            item = get_item_data(infoPtr, cursel);
	    if ((INT_PTR)item == CB_ERR) {
		TRACE("failed to find match??? item=%p cursel=%d\n",
		      item, cursel);
		if (infoPtr->hwndEdit)
		    SetFocus(infoPtr->hwndEdit);
		return 0;
	    }
	}

	/* Save flags for testing and reset them */
	oldflags = infoPtr->flags;
	infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);

	if (oldflags & WCBE_ACTEDIT) {
	    cbeend.fChanged = (oldflags & WCBE_EDITCHG);
	    cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
						 CB_GETCURSEL, 0, 0);
	    cbeend.iWhy = CBENF_DROPDOWN;

	    if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, COMBOEX_GetText(infoPtr, item))) return 0;
	}

	/* if selection has changed the set the new current selection */
	cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
	if ((oldflags & WCBE_EDITCHG) || (cursel != infoPtr->selected)) {
	    infoPtr->selected = cursel;
	    SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, cursel, 0);
	    SetFocus(infoPtr->hwndCombo);
	}
	return 0;

    case CBN_SELCHANGE:
	/*
	 * CB_GETCURSEL(Combo)
	 * CB_GETITEMDATA(Combo)   < simulated by COMBOEX_FindItem
	 * lstrlenA
	 * WM_SETTEXT(Edit)
	 * WM_GETTEXTLENGTH(Edit)
	 * WM_GETTEXT(Edit)
	 * EM_SETSEL(Edit, 0,0)
	 * WM_GETTEXTLENGTH(Edit)
	 * WM_GETTEXT(Edit)
	 * EM_SETSEL(Edit, 0,len)
	 * return WM_COMMAND to parent
	 */
	oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
	if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
	    ERR("item %d not found. Problem!\n", oldItem);
	    break;
	}

⌨️ 快捷键说明

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