Перетащите файлы из папки Zip в мое окно.


Я пытаюсь реализовать функцию, когда содержимое Zip-архива может быть перетащено из папки Zip Проводника Windows в мое окно. Я реализовал все необходимые методы IDropTarget, и все работает нормально, когда я перетаскиваю обычные файлы из Проводника Windows.

Проблема возникает в следующем методе, когда я пытаюсь перетащить файл из папки Zip:

HRESULT DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
    static FORMATETC fmtetc_file = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
    HRESULT hr = pDataObject->QueryGetData(&fmtetc_file);
    if(hr == S_OK)
    {
        //Format supported
    }

    ...
}

Я получаю s_false, возвращенный из QueryGetData ().

Есть ли у кого-нибудь идеи чего мне не хватает?

2 3

2 ответа:

Я не могу себе представить, что обработчик zip-файлов проводника реализует CF_HDROP, поскольку это потребует от него извлечения файлов перед началом перетаскивания. Я держу пари, что он использует CFSTR_FILEDESCRIPTOR и CFSTR_FILECONTENTS .

Кажется, я понял. Не могли бы вы просмотреть этот псевдокод, я не очень хорошо разбираюсь в COM:

Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
{
    FORMATETC fmtetc_file_desc = {RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
    if(pDataObject->QueryGetData(&fmtetc_file_desc) == S_OK)
    {
        STGMEDIUM stgmed;
        if(pDataObject->GetData(&fmtetc_file_desc, &stgmed) == S_OK)
        {
            if(stgmed.tymed & TYMED_HGLOBAL)
            {
                FILEGROUPDESCRIPTOR* pFGD = (FILEGROUPDESCRIPTOR*)::GlobalLock(stgmed.hGlobal);
                for(int f = 0; f < pFGD->cItems; f++)
                {
                    STGMEDIUM stgmedFile = {0};
                    //You may want to move out the RegisterClipboardFormat() API into some global variable
                    FORMATETC fmtetc_file_desc = {RegisterClipboardFormat(CFSTR_FILECONTENTS), 0, DVASPECT_CONTENT, f, TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE};
                    if(pDataObject->GetData(&fmtetc_file_desc, &stgmedFile) == S_OK)
                    {
                        BOOL bReadOK = FALSE;

                        if(!bReadOK && (stgmedFile & TYMED_ISTREAM))
                        {
                            //Now read data from a stream & process it
                            //(If need be, it can be saved in a file)
                            IStream *pstm = pStgmed->pstm;

                            //Size of data in a steam & archived file name
                            STATSTG stg = {0};
                            SUCCEEDED(pstm->Stat(&stg, STATFLAG_DEFAULT) == S_OK);

                            //Then to read data from a stream
                            //Call repeatedly until all or required data is read)
                            SUCCEEDED(pstm->Read(pStorage, ncbBytesRead, &ucbBytesRead));

                            //If read and processed successfully
                            bReadOK = TRUE;


                            //Release mem
                            CoTaskMemFree(stg.pwcsName);

                        }

                        //Probably need to implement these as well?
                        if(!bReadOK && (stgmedFile & TYMED_ISTORAGE))
                        {
                        }
                        if(!bReadOK && (stgmedFile & TYMED_HGLOBAL))
                        {
                        }


                        ReleaseStgMedium(&stgmedFile);;
                    }
                }

                ::GlobalUnlock(stgmed.hGlobal);
            }

            ReleaseStgMedium(&stgmed);

        }
    }

}