tomascz
tomascz

Reputation: 245

MFC: Retrieving dropped data as if they were a file

How do I retrieve global data from a drop operation as if these data were a file? As far as I could find out (on the Internet and in Jeff Procise's "Programming Windows with MFC (2nd ed.)", COleDataObject::GetFileData should be the answer, but I'm doing something wrong, given that the MFC CFile object is created but with an "invalid handle" value (-1).

I'm in fact trying to transfer virtual files (those that don't physically exist on a local drive) between two instance of my application. The transfer works fine between my application and the Windows Explorer (or similar) via HDROP and API DragQueryFile (aka if exporting or importing a physical file).

This is the code that initiates the drag (using CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS formats to transfer virtual files that don't physically exist on a local disk):

// - allocate and fill in the FileGroupDescriptor structure
HGLOBAL hg=::GlobalAlloc( GHND|GMEM_SHARE, ... );
LPFILEGROUPDESCRIPTOR pfgd=::GlobalLock(hg);
    ...
::GlobalUnlock(hg);
// - create an IDataObject instance and put the FileGroupDescriptor     structure into it
// (it holds that cfDescriptor=::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR) )
CCustOleDataSource obj=... // COleDataSource-derived object
FORMATETC etcFileGroupDescriptor={ cfDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
obj.CacheGlobalData( cfDescriptor, hg, &etcFileGroupDescriptor );
// - render the actual data upon request
// (it holds that cfContent=::RegisterClipboardFormat(CFSTR_FILECONTENTS) )
FORMATETC etcFileContents={ cfContent, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
obj.DelayRenderFileData( cfContent, &etcFileContents );
// - perform drag&drop
obj.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE);

This is the code that accepts the drop (works fine if data is retrieved via COleDataObject::GetGlobalData but doesn't function when COleDataObject::GetFileData is used):

// - get the FileGroupDescriptor structure
HGLOBAL hg=pDataObject->GetGlobalData(cfDescriptor);
LPFILEGROUPDESCRIPTOR pfgd=(LPFILEGROUPDESCRIPTOR)::GlobalLock(hg);
// - get a CFile abstraction of the actual data
FORMATETC etcFileContents={ cfContent, NULL, DVASPECT_CONTENT, 0, TYMED_ISTREAM }; // 0 = first dropped file
CFile *f=pDataObject->GetFileData( cfContent, &etcFileContents );
// Problem: "f" created but CFile::m_hFile equals INVALID_HANDLE_VALUE
// - read one sample byte
BYTE b;
f->Read(&b,1);
// - delete the file object
delete f;

Yet a crutial question: Is it actually possible to use CFile objects in combination with delayed rendering? Nevertheless, I can access the delay-rendered data through a global memory pointer.

Any help/suggestion very appreciated, many thanks in advance :-)

Tomas

Upvotes: 0

Views: 366

Answers (1)

tomascz
tomascz

Reputation: 245

Well, it makes sense after all - the CFile::m_hFile equals to INVALID_HANDLE_VALUE as there's no real physical file there, but instad just an abstraction of some non-file data. So the above code works fine - it was just that I didn't get further with the testing than checking out the inner file handle, seeing -1 there.

Problem therefore solved and lesson learned :-)

Upvotes: 1

Related Questions