Question

Drag and drop, delayed rendering, OnRenderGlobalData problem

Asked by: GavinThornton

I am having a bit of trouble with delayed rendering when dragging a file from my app (onto for example a Windows explorer window).

I am getting multiple calls to delay render, most of which I would like to ignore, I only actually want to "render" my data when the file is dropped on a target (like when the user lets go of the mouse button). But OnRenderGlobalData is called numerous times before that including when the file is first dragged, when the drag item passes outside of my apps focus, etc, etc.

I've seen a number of posts in other forums and on here where people have asked the same question, but not one of them has a reply or solution.


This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2006-10-03 at 05:31:13ID22011014
Tags

drag

,

drop

Topic

Windows MFC Programming

Participating Experts
2
Points
0
Comments
11

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. JTree + Renderer + Editor
    Hi, Development Platform is WinNT 4.0 I'm using JDK 1.1/Swing 1.0.3 Another JTree Question: I've implemented my own AttrTreeCellEditor and AttrTreeCellRenderer. The 'Component' which is returned by the 'getTreeCellEditorComponent()' and 'getTreeCellRendererComponent()' meth...
  2. Delayed Rendering in Drag and Drop
    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 unti...
  3. erase() and paint() and render()
    Ok another java drawing question. Is there an 'erase()' method you can override? There seems to be the paint() and render() functions so... and what IS the difference between paint() and render() - why are there two such functions? Thanks
  4. Custom webcontrol rendering
    Hi all, I am creating a custom Panel webcontrol which will act as a "window". I need to place an HTML table around the Panel control with my window design. This works for the most part, meaning that when I run the website and display the panel, I see my custom de...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: AndyAinscowPosted on 2006-10-03 at 06:07:23ID: 17651105

I am a bit uncertain of what your problem is.  You say you only want to render when the file is dropped on the target - the drop should only generate a message once (mouse button up).

 

by: mahesh1402Posted on 2006-10-03 at 07:06:43ID: 17651546

>>I am having a bit of trouble with delayed rendering

better to use COleDataSource::CacheData. Look at this sample
http://download.microsoft.com/download/platformsdk/sample20/1/W351/EN-US/FileDrag.exe

-MAHESH

 

by: GavinThorntonPosted on 2006-10-03 at 08:00:57ID: 17652007

Thats what I expected too. But it generates multiple messages as I said - when first dragged, when passing focus to other applications windows and the final message being when dropped (mouse button up).

I'll give more detail.

I have implemented my own instance of COleDropSource and I am overwriding "virtual BOOL OnRenderGlobalData(LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal);" to recieve the render message.

In my CListControl derived class I have a list of files on a device that I have to read (its not a Windows format). When the user drags file(s) from it and drop them on say an Explorer window, I first get the OnDragDrop message in my list control where I make a list of filenames for my render routine and I tell windows to use my COleDataSource derived class to send the render message to.

So, when my CMyOleDropSource::OnRenderGlobalData routine is called I create my files in a temporary folder and pass the filenames to the drop source. In the case of explorer - the files are then moved to the real destination (the path where they were dropped).

Of course, since "CMyOleDropSource::OnRenderGlobalData" is called multiple times inbetween the drag and the release of the button, I am currently setting a flag in my files list to say I've already created the file, otherwise I end up creating the file X number of times which of course takes too long and is pointless. This solution works OK, but I do end up creating the files unnecissarily if the user ends up not dropping the files somewhere valid.


Here is the code:-

// In my list control, on a drag event, I pass a list of filenames

void CShellListCtrl::OnDragDrop(NM_LISTVIEW* /*pNMListView*/)
{
      TRACE( "CShellListCtrl::OnDragDrop\n" );

      CStringList    *lsSourceDraggedFiles;
      int            nSelItem;
      CString        sFile;

      lsSourceDraggedFiles = new CStringList;                  
      // lsSourceDraggedFiles is my list of files that are being dragged, this is
      // just a list I want my render routine to get so it knows what to render/copy.


      CMyOLEDragDrop *pDataSource = new CMyOLEDragDrop();

      BOOL bAbort = FALSE;
      struct sFileInfo *psFileInfo=NULL;
      POSITION pos = m_pListCtrl->GetFirstSelectedItemPosition();
      while (NULL != pos && !bAbort)                  // Repeat for all drag items
      {            
            nSelItem = m_pListCtrl->GetNextSelectedItem(pos);
            psFileInfo = (struct sFileInfo *)m_pListCtrl->GetItemData(nSelItem);

            if( psFileInfo!=NULL )
            {
                  sFile = psFileInfo->csPath;            // Filename of drag item
      
                  CString csPass;
                  csPass.Format( "%s%i%i", psFileInfo->csPath, psFileInfo->iAttribs, psFileInfo->iPartition );
                  lsSourceDraggedFiles->AddTail(csPass);
            }
      }

      pDataSource->SetCallDatas(lsSourceDraggedFiles, this, m_pWnd);
      pDataSource->DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK);
      delete pDataSource;

      TRACE( "out CShellListCtrl::OnDragDrop(NM_LISTVIEW* /*pNMListView*/)\n" );
      return;
}


// In my COleDropSource derived class

BOOL CMyOleDropSource::OnRenderGlobalData(LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal)
{
      VERIFY(lpFormatEtc->cfFormat==CF_HDROP);

      // Allocate space for DROPFILE structure plus the file path and one extra
      // byte for final NULL terminator
      *phGlobal = GlobalAlloc(GHND|GMEM_SHARE,(DWORD)(sizeof(DROPFILES)+_MAX_PATH+1));

      if (*phGlobal)
      {
            // Make temp file name
            BOOL bAbort = FALSE;
            if( m_plsDraggedFiles != NULL )
            {
                  POSITION       pos;
                  TCHAR          szBuff[MAX_PATH*2];

                  pos = m_plsDraggedFiles->GetHeadPosition();

                  int nSelItem;
                  CString csFile="";
                  CStringList *plsNewList = new CStringList;
                  while (NULL != pos)
                  {
                        lstrcpy (szBuff, (LPCTSTR) m_plsDraggedFiles->GetNext (pos));
                        TRACE( "szBuff=%s\n", szBuff );

                        // Copy the file to our temp folder
                        struct sFileInfo sFileInfo;
                        sFileInfo.csPath = szBuff;
                        sFileInfo.iAttribs = sFileInfo.csPath.GetAt(sFileInfo.csPath.GetLength()-2) - '0';
                        sFileInfo.iPartition = sFileInfo.csPath.GetAt(sFileInfo.csPath.GetLength()-1) - '0';
                        int iLen = sFileInfo.csPath.GetLength();
                        sFileInfo.csPath = sFileInfo.csPath.Left( iLen-2 );

                        // Mark this entry as processed as we get multiple calls to the render routine at present!!!
                        szBuff[_tcslen(szBuff)-2] = 0xff;
                        plsNewList->AddTail(szBuff);

                        CString csDestFile;
                  
                        CString csTemp;                        // Destination on PC (temp folder)
                        csTemp = g_AppPathName;
                        csTemp += "\\Temp\\";
                        if( sFileInfo.iAttribs>=0 )
                        {
                              if( CopyFileOrFolder( &sFileInfo, csTemp, csDestFile )!=0 )
                                    bAbort = TRUE;
                        }
                        else
                        {
                              csDestFile = g_AppPathName;
                              csDestFile += "\\temp\\";
                              CString cs = ExtractFileName( sFileInfo.csPath );
                              csDestFile += cs;
                        }

                        if( !bAbort )
                        {
                              csFile.Append( csDestFile );
                              csFile.Append( "\1" );
                        }
                  }

                  delete m_plsDraggedFiles;
                  m_plsDraggedFiles = plsNewList;

                  if( !bAbort )
                  {
                        int iLen = csFile.GetLength()+2;
                        TCHAR *szStr = (TCHAR*)malloc( iLen );
                        _tcscpy( szStr, csFile.GetBuffer() );
                        TRACE( "To Exp: %s\n", szStr );
                        ReplaceAllChars( szStr, '\1', '\0' );

                        // Last string will end with two 0 bytes.

                        LPDROPFILES pDropFiles;
                        pDropFiles = (LPDROPFILES)GlobalLock(*phGlobal);

                        // Set the offset where the starting point of the file start
                        pDropFiles->pFiles = sizeof(DROPFILES);

                        // File doesn't contain wide characters
                        pDropFiles->fWide=FALSE;

                        // Copy file name.
                        memcpy(((LPSTR)pDropFiles)+sizeof(DROPFILES), (LPCSTR)szStr, iLen*sizeof(TCHAR));
                        free( szStr );
                  }
            }

            GlobalUnlock(*phGlobal);
            return TRUE;
      }
     
      return *phGlobal!=NULL;
}

 

by: GavinThorntonPosted on 2006-10-03 at 08:03:18ID: 17652031

Sorr, in the above post, I meant I am using "COleDataSource", not COleDropSource!

 

by: GavinThorntonPosted on 2006-10-03 at 08:11:18ID: 17652109

> better to use COleDataSource::CacheData. Look at this sample
> http://download.microsoft.com/download/platformsdk/sample20/1/W351/EN-US/FileDrag.exe
> -MAHESH

Thanks for the comment MAHESH. I've expanded my explanation of my problem, I am using COleDataSource and hence COleDataSource::OnRenderGlobalData.

I am using CF_HDROP format.

That sample doesn't work by the way, it doesn't run properly in VC++ 6 or 7 I think it is just a very old Win32 sample that doesn't quite work anymore; But as in the sample, that is essentially what I am doing.

It all works fine apart from getting multiple calls to OnRenderGlobalData. I assume what is happening is that other windows who see the drag item passing over them, take a sneaky peek at what is being dragged and cause me to have to render the data. When I only really want to do is render the data when the real drop happens (the user lets go of the mouse button on an explorer window or editor).


 

by: AndyAinscowPosted on 2006-10-03 at 08:22:16ID: 17652202

<When I only really want to do is render the data when the real drop happens (the user lets go of the mouse button on an explorer window or editor).>

Still puzzled - why not just do that, ignore the requests to render inbetween (OR do you not get the chance to render when it is dropped?)

 

by: GavinThorntonPosted on 2006-10-03 at 08:54:02ID: 17652441

In reply to Andy:

The whole thing relies on me getting a "CMyOleDropSource::OnRenderGlobalData" message when the drop target (say an explorer window) tells me that it wants the data. Unfortunatly, "CMyOleDropSource::OnRenderGlobalData" gets called by other things like the focus changing as the item is dragged. The very last call will be when the user has actually dropped (released the mouse button).

When writing the code I expected "CMyOleDropSource::OnRenderGlobalData" to only get called when the mouse button is released over a drop target but it doesn't.

My problem is - I don't know when the last call is, or when the user has actually let go of the mouse button.

The passed parameters to "BOOL CMyOleDropSource::OnRenderGlobalData(LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal)"';  "LPFORMATETC lpFormatEtc" and "HGLOBAL* phGlobal" are exactly the same for each call.

 

by: GavinThorntonPosted on 2006-10-03 at 09:03:58ID: 17652521

Hold on, I have found a solution:

I have implemented a class COleDropSource derived class and passed it to the call of DoDragDrop in my OnDragDrop function.


class CMyDropSource : public COleDropSource
{
public:
      CMyDropSource(CMyOLEDragDrop *pDataSourceParam);
      virtual ~CMyDropSource();
      virtual SCODE QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState);
private:
      CMyOLEDragDrop *pDataSource;
};


// Added this to the bottom of my OnDragDrop (changing the existing call to pDataSource->DoDragDrop)

      CMyDropSource DropSource(pDataSource);
      pDataSource->DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK, 0, &DropSource);


Now I can track the drag in the QueryContinueDrag override:

CMyDropSource::CMyDropSource(CMyOLEDragDrop *pDataSourceParam)
: COleDropSource()
, pDataSource(pDataSourceParam)
{}

CMyDropSource::~CMyDropSource()
{
      //delete pDataSource;
}

SCODE CMyDropSource::QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState)
{
      SCODE sCode = COleDropSource::QueryContinueDrag(bEscapePressed, dwKeyState);
      if ( sCode == DRAGDROP_S_DROP ) {
            if ( pDataSource != NULL )
                  pDataSource->some function to say it is actually dropped...
      }
      return sCode;
}


 

by: mahesh1402Posted on 2006-10-04 at 02:58:49ID: 17658017

Here is how It can be used :

STDMETHODIMP CDropSource::GiveFeedback(DWORD dwEffect)
{
    return DRAGDROP_S_USEDEFAULTCURSORS;
}

STDMETHODIMP CDropSource::QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState)
{
   
   if ( bEscapePressed)       // If ESC was pressed, cancel the drag.        
       return DRAGDROP_S_CANCEL;
   else
   if ( (dwKeyState & MK_LBUTTON) ==0)   // If the left button was released, continue with the drag-drop
        return DRAGDROP_S_DROP;
   else
        return S_OK; // continue with the drag-drop
}

-MAHESH

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...