P>>Не подскажете где икать информацию по реализации сабжа,
P>>под сабжем подразумеваю следующее:
P>> И как он правильно называется.

A>Называется это Auto Complete. Начать поиск можно с функции SHAutoComplete и интерфейса IAutoComplete.


SHAutoComplete — самый простой способ, но он позволяет вводить только URL'ы и имена файлов.

Если тебе нужно запоминать любой текст, то придется юзать IAutoComplete. Для этого создаешь объект
    CComPtr<IAutoComplete> AutoComplete;

и инициализируешь его

    AutoComplete->Init(GetDlgItem(IDC_CMD), m_SS, NULL, NULL);
    CComQIPtr<IAutoComplete2> ac2(AutoComplete);
    ac2->SetOptions(ACO_AUTOAPPEND|ACO_AUTOSUGGEST|ACO_UPDOWNKEYDROPSLIST);

Вторым параметром передается интерфейс, управляющий выводом строк в выпадающий список, их хранением и т.д. Он должен уметь предоставлять интерфейс IEnumSrting. Чтобы долго не мучаться я поступил просто: создал класс, производный от IEnumSrting

class CStringStorage : public IEnumString
    {
    ...
    };

и реализовал все требуемые методы. В частности, QueryInterface выглядит так:

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)
        {
        HRESULT hr = E_NOINTERFACE;
        if(ppvObject == NULL)
            return E_POINTER;

        *ppvObject = NULL;
        if(riid == IID_IUnknown)
            *ppvObject = static_cast<IUnknown*>(this);
        if(riid == IID_IEnumString)
            *ppvObject = static_cast<IEnumString*>(this);
        if(*ppvObject != NULL)
            {
            ((LPUNKNOWN)*ppvObject)->AddRef();
            return S_OK;
            }
        return E_NOINTERFACE;
        }

Методы IEnumString'а (Next, Skip, Reset) реализуешь сам в зависимости от того, где будут храниться запомненные строки.
Самый сложный вопрос, на который мне так никто и не ответил
Автор: SWW
Дата: 15.02.05
заключается в том, как удалять ненужные строки. Но мне таки удалось это сделать. Оказывается, еще есть интерфейс IAutoCompleteDropDown котрый в MSDN почему-то не описан. Получить его можно из IAutoComplete

    CComQIPtr<IAutoCompleteDropDown> acdd(AutoComplete);

В нем есть два метода: ResetEnumerator(void) и GetDropDownStatus(/*[out]*/ DWORD *pdwFlags, /*[string][out]*/ LPWSTR *ppwszString). Первый вызывает повторное заполнение списка, а с помощью второго можно получить информацию о текущем состоянии вывавшего списка. Для этого я встроил его в PreTranslateMessage и проверяю: если нажата клавиша <del> && список при этом открыт, то вызывается функция CStringStorage для удаления выделенной строки:

BOOL CSendDlg::PreTranslateMessage(MSG* pMsg)
    {
    if(pMsg->message != WM_KEYDOWN || pMsg->wParam != VK_DELETE)
        return IsDialogMessage(pMsg);

    CComQIPtr<IAutoCompleteDropDown> acdd(AutoComplete);
    if(acdd)
        {
        DWORD Flag = 0;
        LPWSTR Cmd = NULL;
        acdd->GetDropDownStatus(&Flag, &Cmd);
        if((Flag & ACDD_VISIBLE) != 0 && Cmd != NULL)
            {
            m_SS->RemoveCmd(Cmd);
            ::CoTaskMemFree(Cmd);
            CWindow wndCmd = GetDlgItem(IDC_CMD);
            wndCmd.SetWindowText(_T(""));
            acdd->ResetEnumerator();
            wndCmd.PostMessage(WM_KEYDOWN, VK_DOWN);
            }
        }
    return IsDialogMessage(pMsg);
    }

PostMessage(WM_KEYDOWN, VK_DOWN) нужен для того, чтобы вновь отобразить выпавший список с новым содержимым (т.к. после нажатия на <del> он закрывается).
Автор: SWW    Оценить