Извлечение функции в программировании расширений оболочки

#winapi #visual-c

#winapi #visual-c

Вопрос:

Я хочу извлечь некоторый код DropHandler в отдельную функцию, но понятия не имею, как это сделать при работе с указателями интерфейса или C в целом. Я хочу получить только первый элемент в DragEnter , используя отдельную функцию.

 HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray* items, IShellItem* first_item)
{
    HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(amp;items));
    if (hr != ERROR_SUCCESS)
    {
        return E_INVALIDARG;
    }

    DWORD item_count;
    items->GetCount(amp;item_count);
    if (item_count != 1)
    {
        items->Release();
        return E_INVALIDARG;
    }

    hr = items->GetItemAt(0, amp;first_item);
    if (hr != ERROR_SUCCESS)
    {
        items->Release();
        return E_INVALIDARG;
    }

    return ERROR_SUCCESS;
}

HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
    IShellItemArray* items = nullptr;
    IShellItem* dragged_item = nullptr;
    HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
    if (hr != ERROR_SUCCESS)
    {
        return E_INVALIDARG;
    }

    //...use dragged_item
  

Эта попытка кода приводит к значительному сбою проводника. Я не уверен, какую сигнатуру функции и указатели я должен использовать, чтобы заставить ее работать.

Редактировать: исправлен ответ для каждого пользователя

 HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray*amp; items, IShellItem*amp; first_item)
{
    HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(amp;items));
    if (hr != ERROR_SUCCESS)
    {
        return E_INVALIDARG;
    }

    DWORD item_count;
    hr = items->GetCount(amp;item_count);
    if (hr != ERROR_SUCCESS || item_count != 1)
    {
        items->Release();
        return E_INVALIDARG;
    }

    hr = items->GetItemAt(0, amp;first_item);
    if (hr != ERROR_SUCCESS)
    {
        items->Release();
        return E_INVALIDARG;
    }

    return ERROR_SUCCESS;
}

HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
    IShellItemArray* items;
    IShellItem* dragged_item;
    HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
    if (hr != ERROR_SUCCESS)
    {
        return E_INVALIDARG;
    }

    //...use dragged_item
  

Ответ №1:

Ваша обработка IShellItemArray* и IShellItem* неверна. GetFirstItem освободится IShellItemArray* при сбое, но при успехе вы пропустите его и first_item никогда не будете возвращены правильно. items и first_item в DragEnter никогда не будут действительными.

IShellItemArray* вероятно, должна быть локальная переменная в GetFirstItem .

IShellItem* first_item Параметр должен быть IShellItem** first_item или IShellItem*amp; first_item , чтобы значение указателя правильно возвращалось вызывающей стороне.

Вы никогда не проверяете возвращаемое значение GetCount .

Поскольку у вас возникли проблемы с указателями, вы можете захотеть добавить некоторые assert s, чтобы убедиться, что указатели вашего интерфейса не равны нулю, прежде чем использовать их.

Комментарии:

1. Спасибо! Используя IShellItem*amp; в качестве аргумента, он компилируется и отлично работает! Причина, по которой мне нужно принести IShellItemArray* извне, заключается в том, что я могу выпустить ее позже.