ahmd0
ahmd0

Reputation: 17313

Drag-and-drop files from a Zip folder into my window

I'm trying to implement a feature when contents of a Zip archive could be dragged-and-dropped from a Windows Explorer's Zip folder into my window. I implemented all necessary methods of IDropTarget and everything works fine when I drag-n-drop regular files from the Windows Explorer.

The issue happens in the following method when I attempt to drag in a file from a Zip folder:

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
    }

    ...
}

I get S_FALSE returned from QueryGetData().

Does anyone have any idea what am I missing?

Upvotes: 5

Views: 3238

Answers (2)

ahmd0
ahmd0

Reputation: 17313

I think I got it. Could you review this pseudo-code, I'm not really good at 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);

        }
    }

}

Upvotes: 1

Luke
Luke

Reputation: 11431

I can't imagine Explorer's zip file handler implements CF_HDROP as that would require it to extract the files before initiating the drag. I am betting it uses CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS.

Upvotes: 3

Related Questions