Solved

Delayed Rendering in Drag and Drop

Posted on 2001-09-03
13
819 Views
Last Modified: 2013-11-20
Hai.

I am jagadeesh. Right now I am developing a windows explorer type application for zipped files as my academic project. I want to implement the drag and drop feature by which the user could drag files on to the explorer. The problem i have is,I want explorer to wait until the requested file has been unzipped. So i tried with delayed rendering, but it's not working ( I think i was wrong in percieving the concept of delayed rendering ). Can anybody help me by giving me a right solution.

Rgds
Jagadeesh
0
Comment
Question by:coxswainindia
  • 5
  • 4
  • 2
  • +1
13 Comments
 
LVL 2

Expert Comment

by:BogdyPtr
ID: 6450396
Can you post the pieces of code that make the drag possible.

U can unzip the files before the drag begin(bad solution for big files ) or U can use a COleDataSource derived class for the drag and drop opperation and use the DelayRenderData function to expose your data and then overrite the OnRenderData function or OnRenderGlobalData and unzip files inside these functions.
0
 

Author Comment

by:coxswainindia
ID: 6452093
I did the same.
Then I've 2 problems.

1. OnRenderGlobalData is called several times by the frame work.that i think i can manage.

2. The explorer doesn't even recognize the CF_HDROP format. It's behaving as if nothing was dropped there.

Pls have a look at the code.

void CMultiFilerDlg::OnBegindragFiles(NMHDR* pNMHDR, LRESULT* pResult)
{
COleDataSourceEx datasrc;   // COleDataSource Derived Class
        .
        .
        .   // Other Variable initilizations
HGLOBAL        hgDrop;

uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1);
hgDrop = GlobalAlloc ( GHND | GMEM_SHARE, uBuffSize );
pDrop = (DROPFILES*) GlobalLock ( hgDrop );
pDrop->pFiles = sizeof(DROPFILES);
pos = lsDraggedFiles.GetHeadPosition();
pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES));

while ( NULL != pos )
{
lstrcpy ( pszBuff, (LPCTSTR) lsDraggedFiles.GetNext ( pos ) );
pszBuff = 1 + _tcschr ( pszBuff, '\0' );
}
GlobalUnlock ( hgDrop );
datasrc.hgDrop = hgDrop;
//datasrc.CacheGlobalData ( CF_HDROP, hgDrop, &etc );
datasrc.DelayRenderData ( CF_HDROP );

The same is done with a custom clipboard format.
The DoDragDrop is called.
}



BOOL COleDataSourceEx::OnRenderGlobalData( LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal )
{
// hgDrop is the Global data
if( lpFormatEtc->cfFormat == CF_HDROP )
{
*phGlobal = hgDrop;
return (phGlobal != NULL);
}
return FALSE;

}


This same piece of code is working nicely with CacheGlobalData method

Can U suggest a solution????
0
 
LVL 2

Assisted Solution

by:BogdyPtr
BogdyPtr earned 37 total points
ID: 6452646

Maybe u can find this link useful. It is a sample. Maybe is better to use COleDataSource::CacheData.

http://download.microsoft.com/download/platformsdk/sample20/1/W351/EN-US/FileDrag.exe
0
 

Author Comment

by:coxswainindia
ID: 6452891
Its working fine with CacheData. But the thing is I'm using the same piece of code with DelayRenderData and it's working when dropped on MS Word / Notepad / any other OLE server. Do I've to do anything more to make it work with windows explorer ??

U'r suggestions are invited
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6453082
In your implementaiton of OnRenderGlobalData(...) how are you building/accessoring/storing the data in "hgDrop"?

-=- James.
0
 

Author Comment

by:coxswainindia
ID: 6462928
This is how the HGLOBAL is filled

HGLOBAL        hgDrop;
DROPFILES*     pDrop;


uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1);
pDrop = (DROPFILES*) GlobalLock ( hgDrop );
pDrop->pFiles = sizeof(DROPFILES);

#ifdef _UNICODE
    pDrop->fWide = TRUE;
#endif;

hgDrop = GlobalAlloc ( GHND | GMEM_SHARE, uBuffSize );
pDrop = (DROPFILES*) GlobalLock ( hgDrop );
pDrop->pFiles = sizeof(DROPFILES);
pos = lsDraggedFiles.GetHeadPosition();
pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES));

while ( NULL != pos )
{
lstrcpy ( pszBuff, (LPCTSTR) lsDraggedFiles.GetNext ( pos ) );
pszBuff = 1 + _tcschr ( pszBuff, '\0' );
}
GlobalUnlock ( hgDrop );
...

0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 4

Expert Comment

by:jtwine100697
ID: 6464036
I must be missing something:

   o pDrop points to the return value of GlobalLock( hgDrop ), but I do not see where hgDrop is initialized before that.
   o The "fWide" flag is only touched for Unicode builds, but since the pDrop memory is not initialized at this point (only after the GlobalAlloc is the memory zero-initialized) there may still be a non-zero value in the flag.
   o You then reassign the pDrop pointer, so whatever changes to it you made before would be lost(?).
   o What is "IsDraggedFiles"?

Please post the code for the entire function, from parameter list to last closing brace.

-=- James.
0
 

Author Comment

by:coxswainindia
ID: 6469533

void CMultiFilerDlg::OnBegindragFilelist(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLISTVIEW*    pNMLV = (NMLISTVIEW*) pNMHDR;
COleDataSourceEx datasrc;
HGLOBAL        hgDrop;
DROPFILES*     pDrop;
CStringList    lsDraggedFiles;
POSITION       pos;
int            nSelItem;
CString        sFile;
UINT           uBuffSize = 0;
TCHAR*         pszBuff;
FORMATETC      etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };

    *pResult = 0;   // return value ignored

    // For every selected item in the list, put the filename into lsDraggedFiles.

    pos = c_FileList.GetFirstSelectedItemPosition();

    while ( NULL != pos )
        {
        nSelItem = c_FileList.GetNextSelectedItem ( pos );
        sFile = c_FileList.GetItemText ( nSelItem, 0 );

        lsDraggedFiles.AddTail ( sFile );

        // Calculate the # of chars required to hold this string.

        uBuffSize += lstrlen ( sFile ) + 1;
        }

    // Add 1 extra for the final null char, and the size of the DROPFILES struct.

    uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1);

    // Allocate memory from the heap for the DROPFILES struct.

    hgDrop = GlobalAlloc ( GHND | GMEM_SHARE, uBuffSize );

    if ( NULL == hgDrop )
        return;

    pDrop = (DROPFILES*) GlobalLock ( hgDrop );

    if ( NULL == pDrop )
        {
        GlobalFree ( hgDrop );
        return;
        }

    // Fill in the DROPFILES struct.

    pDrop->pFiles = sizeof(DROPFILES);

#ifdef _UNICODE
    // If we're compiling for Unicode, set the Unicode flag in the struct to
    // indicate it contains Unicode strings.

    pDrop->fWide = TRUE;
#endif;

    // Copy all the filenames into memory after the end of the DROPFILES struct.

    pos = lsDraggedFiles.GetHeadPosition();
    pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES));

    while ( NULL != pos )
        {
        lstrcpy ( pszBuff, (LPCTSTR) lsDraggedFiles.GetNext ( pos ) );
        pszBuff = 1 + _tcschr ( pszBuff, '\0' );
        }

    GlobalUnlock ( hgDrop );

    // Put the data in the data source.

    datasrc.hgDrop = hgDrop;
    datasrc.DelayRenderData( CF_HDROP, &etc );

    // Add in our own custom data, so we know that the drag originated from our
    // window.  CMyDropTarget::DragEnter() checks for this custom format, and
    // doesn't allow the drop if it's present.  This is how we prevent the user
    // from dragging and then dropping in our own window.
    // The data will just be a dummy bool.
    // Infact we'r never using the hgBool

HGLOBAL hgBool;

    hgBool = GlobalAlloc ( GHND | GMEM_SHARE, sizeof(bool) );

    if ( NULL == hgBool )
        {
        GlobalFree ( hgDrop );
        return;
        }

    // Put the data in the data source.

    etc.cfFormat = g_uCustomClipbrdFormat;
    datasrc.hgBool = hgBool;
    datasrc.DelayRenderData ( g_uCustomClipbrdFormat, &etc );


    // Start the drag 'n' drop!

DROPEFFECT dwEffect = datasrc.DoDragDrop ( DROPEFFECT_COPY | DROPEFFECT_MOVE );

    // If the DnD completed OK, we remove all of the dragged items from our
    // list.

    switch ( dwEffect )
        {
        case DROPEFFECT_COPY:
        case DROPEFFECT_MOVE:
            {
            // Note: Don't call GlobalFree() because the data will be freed by the drop target.

            for ( nSelItem = c_FileList.GetNextItem ( -1, LVNI_SELECTED );
                  nSelItem != -1;
                  nSelItem = c_FileList.GetNextItem ( nSelItem, LVNI_SELECTED ) )
                {
                c_FileList.DeleteItem ( nSelItem );
                nSelItem--;
                }

            // Resize the list columns.

            c_FileList.SetColumnWidth ( 0, LVSCW_AUTOSIZE_USEHEADER );
            c_FileList.SetColumnWidth ( 1, LVSCW_AUTOSIZE_USEHEADER );
            c_FileList.SetColumnWidth ( 2, LVSCW_AUTOSIZE_USEHEADER );
            }
        break;

        case DROPEFFECT_NONE:
            {
            // This needs special handling, because on NT, DROPEFFECT_NONE
            // is returned for move operations, instead of DROPEFFECT_MOVE.
            // See Q182219 for the details.
            // So if we're on NT, we check each selected item, and if the
            // file no longer exists, it was moved successfully and we can
            // remove it from the list.

            if ( g_bNT )
                {
                bool bDeletedAnything = false;

                for ( nSelItem = c_FileList.GetNextItem ( -1, LVNI_SELECTED );
                      nSelItem != -1;
                      nSelItem = c_FileList.GetNextItem ( nSelItem, LVNI_SELECTED ) )
                    {
                    CString sFilename = c_FileList.GetItemText ( nSelItem, 0 );

                    if ( 0xFFFFFFFF == GetFileAttributes ( sFile ) &&
                         GetLastError() == ERROR_FILE_NOT_FOUND )
                        {
                        // We couldn't read the file's attributes, and GetLastError()
                        // says the file doesn't exist, so remove the corresponding
                        // item from the list.

                        c_FileList.DeleteItem ( nSelItem );
                   
                        nSelItem--;
                        bDeletedAnything = true;
                        }
                    }

                // Resize the list columns if we deleted any items.

                if ( bDeletedAnything )
                    {
                    c_FileList.SetColumnWidth ( 0, LVSCW_AUTOSIZE_USEHEADER );
                    c_FileList.SetColumnWidth ( 1, LVSCW_AUTOSIZE_USEHEADER );
                    c_FileList.SetColumnWidth ( 2, LVSCW_AUTOSIZE_USEHEADER );

                    // Note: Don't call GlobalFree() because the data belongs to
                    // the caller.
                    }
                else
                    {
                    // The DnD operation wasn't accepted, or was canceled, so we
                    // should call GlobalFree() to clean up.

                    GlobalFree ( hgDrop );
                    GlobalFree ( hgBool );
                    }
                }   // end if (NT)
            else
                {
                // We're on 9x, and a return of DROPEFFECT_NONE always means
                // that the DnD operation was aborted.  We need to free the
                // allocated memory.

                GlobalFree ( hgDrop );
                GlobalFree ( hgBool );
                }
            }
        break;  // end case DROPEFFECT_NONE
        }   // end switch
}


//Implementation of COleDataSourceEx::OnRenderGlobalData
//COleDataSourceEx contains two member variables
HGLOBAL hgDrop;
HGLOBAL hgBool;

BOOL COleDataSourceEx::OnRenderGlobalData( LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal )
{

if( lpFormatEtc.cfFormat == CF_HDROP )
{
    *phGlobal = hgDrop;
    return (phGlobal != NULL );
}
    return FALSE;
}
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6470901
Unless I am just missing something, I am not noticing anything wrong with the function; but I continue to wonder if you are not using delayed rendering in an incorrect fashion.

IIRC, delayed rendering is used to prevent supplying data until it is asked for.  For example, "Copy"ing a bitmap to the clipboard, but not *really* putting a bitmap there until someone actually tries to "Paste" it someplace.  It is not supposed to be used as "OK, wait here while I get the bitmap ready".  If you want Explorer to wait for you to extract the file (since you are doing copies and moves, not shortcuts), make the extraction part of the D&D transfer.

-=- James.
0
 

Author Comment

by:coxswainindia
ID: 6473055
Thanx for u'r reply

I got u'r point.
Cud u pls help me by suggesting a workaround. I want explorer to wait until i extract the file.
I've a doubt on what u meant by
"If you want Explorer to wait for you to extract the file (since you are doing copies and moves, not shortcuts),
make the extraction part of the D&D transfer"

At what point shud i extract the file ??
I shudn't do that on BeginDrag(). Isn't it ?
It will give undesired results if the file size is greater than say 1MB or so..

so where shud i start extracting the files??
0
 
LVL 4

Accepted Solution

by:
jtwine100697 earned 38 total points
ID: 6476810
At the point of the drop, as the drag may get canceled.  The same way that WinZIP does it.

-=- James.
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 9531984
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Answered by: BogdyPtr, jtwine (points to be split)

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Roshan Davis
EE Cleanup Volunteer
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now