将Zip文件夹中的文件拖放到我的窗口中

时间:2011-05-13 09:40:43

标签: c++ zip windows-explorer

我正在尝试实现一项功能,可以将Zip存档的内容从Windows资源管理器的Zip文件夹拖放到我的窗口中。我实现了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
    }

    ...
}

我从QueryGetData()返回S_FALSE。

有没有人知道我错过了什么?

2 个答案:

答案 0 :(得分:3)

我无法想象Explorer的zip文件处理程序实现CF_HDROP,因为它需要它在启动拖动之前提取文件。我打赌它使用CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS

答案 1 :(得分:1)

我想我明白了。你能不能看一下这个伪代码,我不是很擅长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);

        }
    }

}