Solved

CListCtrl and Drag and Drop

Posted on 1998-06-10
26
1,068 Views
Last Modified: 2008-02-01
I've got a list view in which I've got a list of files.  I'd like to have the use select some files and then drag then out to another folder where it copies those files.  Explorer does this very thing everyday so I know it's possible.
This will become worth more points once I have them available.
0
Comment
Question by:ElmerFud
  • 14
  • 12
26 Comments
 
LVL 10

Accepted Solution

by:
RONSLOW earned 30 total points
Comment Utility
Construct a COleDataSource object when you get a begin drag message in you list view, initialize it with the filename of the corresponging item (in CF_FILENAME format), and call the data source object's DoDragDrop member function.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
something like this ...

CString name = ... file name of selected item
int buflen = name.GetLength() + 1;
HANDLE hData =
::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, buflen);
LPTSTR* pString = (LPTSTR)::GlobalLock (hData);
strcpy(pString,string);
::GlobalUnlock (hData);
COleDataSource ods;
ods.CacheGlobalData (CF_FILENAME, hData);
ods.DoDragDrop (DROPEFFECT_COPY);


0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Better is to use CF_HDROP instead of CF_FILENAME

Set up a DROPFILES object .. this supports a list of file name (double null terminated)

Lookup DROPFILE or CF_HDROP in the on-line help for further info

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
ok, I'm gonna try it.  I'm kind of confused as to where I should put this code, is there some event that is related to the user trying to drag an item from the ListView?  I'm gonna play around with it this morning and see what I come up with.  I've got 5 more points today.  This is worth 50 easy, I just didn't hav ethe points yesterday.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
I'd try a handler for LVN_BEGINDRAG.

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
Ahhh!  That makes since.  :)  Gonna try it right now.  Be back ASAP.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Good luck .. I haven't tried it myself yet (got my own problems at the moment) .. but you should have the concept at least.  I'll give it a go myself ASAP .. when the panic subsides

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
Ahhh!  That makes since.  :)  Gonna try it right now.  Be back ASAP.
0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
I'm most certainly doing this wrong.  I'm very confused.  :) Here's my function.  I don't think I'm doing the multiple files thingy right. There is very little documentation on the clipboard formats which are built into Visual C++.

void CNoteDlg::OnBegindragFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  CString Files = "";
  int i = m_FileList.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);
  while( i != -1 )
  {
    Files += CurDir + "Recieved Files\\" + m_FileList.GetItemText(i, 0) + "\0\0";
    i = m_FileList.GetNextItem(i, LVNI_ALL | LVNI_SELECTED);
  }

  HANDLE hData = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, Files.GetLength() + 1);
  LPTSTR pString = (LPTSTR)::GlobalLock (hData);
  strcpy(pString, Files);
  ::GlobalUnlock (hData);
  COleDataSource ods;
  ods.CacheGlobalData(CF_HDROP, hData);
  ods.DoDragDrop (DROPEFFECT_COPY);
  GlobalFree(hData);
      
  *pResult = 0;
}

i'm pretty sure this line is wrong:
  ods.CacheGlobalData(CF_HDROP, hData);
I need to turn it into the right data structure.  I'm gonna fiddle with it some more.  Anyway Good luck with your troubles there.  Answer when ever you can.  I frequently find myself putting out the flames.  :)
-ElmerFud

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
I'm most certainly doing this wrong.  I'm very confused.  :) Here's my function.  I don't think I'm doing the multiple files thingy right. There is very little documentation on the clipboard formats which are built into Visual C++.

void CNoteDlg::OnBegindragFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  CString Files = "";
  int i = m_FileList.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);
  while( i != -1 )
  {
    Files += CurDir + "Recieved Files\\" + m_FileList.GetItemText(i, 0) + "\0\0";
    i = m_FileList.GetNextItem(i, LVNI_ALL | LVNI_SELECTED);
  }

  HANDLE hData = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, Files.GetLength() + 1);
  LPTSTR pString = (LPTSTR)::GlobalLock (hData);
  strcpy(pString, Files);
  ::GlobalUnlock (hData);
  COleDataSource ods;
  ods.CacheGlobalData(CF_HDROP, hData);
  ods.DoDragDrop (DROPEFFECT_COPY);
  GlobalFree(hData);
      
  *pResult = 0;
}

i'm pretty sure this line is wrong:
  ods.CacheGlobalData(CF_HDROP, hData);
I need to turn it into the right data structure.  I'm gonna fiddle with it some more.  Anyway Good luck with your troubles there.  Answer when ever you can.  I frequently find myself putting out the flames.  :)
-ElmerFud

0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
You cannot build up strings with embedded '\0' in them using CString .. as it takes the nul char as meaning the end of string.

I suggest building the CString with, say, ';' separators, then doing a strdup on it and changing all the ';' into '\0'.  Or just build it up in a char[] buffer yourself.

Then try again.

PS: You probably graded too early on this one .. if you cannot get it to work then other experts cannot come in here to help you further (if I am unable to do so).

But thanks anyway for the points and appreciation.

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
I'm most certainly doing this wrong.  I'm very confused.  :) Here's my function.  I don't think I'm doing the multiple files thingy right. There is very little documentation on the clipboard formats which are built into Visual C++.

void CNoteDlg::OnBegindragFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

  CString Files = "";
  int i = m_FileList.GetNextItem( -1, LVNI_ALL | LVNI_SELECTED);
  while( i != -1 )
  {
    Files += CurDir + "Recieved Files\\" + m_FileList.GetItemText(i, 0) + "\0\0";
    i = m_FileList.GetNextItem(i, LVNI_ALL | LVNI_SELECTED);
  }

  HANDLE hData = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, Files.GetLength() + 1);
  LPTSTR pString = (LPTSTR)::GlobalLock (hData);
  strcpy(pString, Files);
  ::GlobalUnlock (hData);
  COleDataSource ods;
  ods.CacheGlobalData(CF_HDROP, hData);
  ods.DoDragDrop (DROPEFFECT_COPY);
  GlobalFree(hData);
      
  *pResult = 0;
}

i'm pretty sure this line is wrong:
  ods.CacheGlobalData(CF_HDROP, hData);
I need to turn it into the right data structure.  I'm gonna fiddle with it some more.  Anyway Good luck with your troubles there.  Answer when ever you can.  I frequently find myself putting out the flames.  :)
-ElmerFud

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
I just learned a good lesson.  don't use the reload button in Expert's Exchange  :)  I'll try that.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
Why am I getting this error?

E:\Projects\cpp\vtifs\NoteDlg.cpp(420) : error C2065: 'CF_FILENAME' : undeclared identifier

I searched for it and I got:

Searching for 'CF_FILENAME'...
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2235):#define CFSTR_FILENAMEA         TEXT("FileName")                // CF_FILENAMEA
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2236):#define CFSTR_FILENAMEW         TEXT("FileNameW")               // CF_FILENAMEW
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2238):#define CFSTR_FILENAMEMAPA      TEXT("FileNameMap")             // CF_FILENAMEMAPA
C:\Program Files\devstudio\VC\include\SHLOBJ.H(2239):#define CFSTR_FILENAMEMAPW      TEXT("FileNameMapW")            // CF_FILENAMEMAPW
4 occurrence(s) have been found.

so I did:
#include <SHLOBJ.H>

I thought maybe I could get it to do one file.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Use CF_HDROP instead - it allows multiple files [if you can build the string :-)]

If you want the CF_FILENAME format .. use CF_FILENAMEA (unless you are using UNICODE)

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
I see.  I was using CF_DROP, but I couldn't get that to work so I went for the one fie drag.  There is no on-line help for CF_HDROP.  It is refered to in several places, but never defined.  I'll keep trying.  There is a definition for DROPFILE, but that doesn't do me any good.
0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
CF_FILENAMEA is also undeclared
0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
typedef struct _DROPFILES {
    DWORD pFiles; // offset of file list
    POINT pt;     // drop point (coordinates depend on fNC)
    BOOL fNC;     // see below
    BOOL fWide;   // TRUE if file contains wide characters,
                  // FALSE otherwise
} DROPFILES, FAR * LPDROPFILES

what is the "offset of file list"?  I've been passing in a pointer to the filelist.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
oops meant CFSTR_FILENAMEA

anyway .. docs say ...
===
CF_HDROP format

The global memory object contains a DROPFILES structure. If the object was copied to the clipboard as part of a drag-and-drop operation, the pt member of DROPFILES includes the coordinates of the point where the drop occurred. The pFiles member is the offset to a double null-terminated list of file names. An application can retrieve information from the data object by passing the object's handle to the DragQueryFile and DragQueryPoint functions.
===

so .. if you place the list of names directly after the DROPFILES struct then pFiles would be 'sizeof(DROPFILES)' (I guess).

0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
I got this from online help on CF_HDROP (I've got MSDN though .. but should be in platform SDK help?)

There isn't a lot though.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
There is a MS sample callsed FILEDRAG.EXE that you can donwload from MS FTP site .. it might help

0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
It has a routine...

HGLOBAL CreateHDrop()
{
  HGLOBAL hGlobal;
  // for my sample I am assuming number of files as 2
  int cnt = 2;
  // allocate space for DROPFILE structure plus the number of
  // file and one extra byte for final NULL terminator
  hGlobal = GlobalAlloc(GHND|GMEM_SHARE,(DWORD) (sizeof(DROPFILES)+(_MAX_PATH)*cnt+1));
  if(hGlobal == NULL) return hGlobal;
  LPDROPFILES pDropFiles;
  pDropFiles = (LPDROPFILES)GlobalLock(hGlobal);
  // set the offset where the starting point of the file start
  pDropFiles->pFiles = sizeof(DROPFILES);
  // file does not contain wide characters
  pDropFiles->fWide=FALSE;
  int CurPosition = sizeof(DROPFILES);
  for (int i = 0;i < cnt;i++) {
    TCHAR pszTempPath[MAX_PATH];
    TCHAR szFileName[_MAX_PATH];
    //Get File Name
    wsprintf(szFileName, "myfile%d.txt",i);
    // Create the Temp FileName, Also Note, I don't delete it.
    // since the file has exist on the hard drive. for an
    //application to open it.
    // if I delete it this will not work.
    CreateMyTempFile(szFileName, pszTempPath);
    // copy the file into global memory
    lstrcpy((LPSTR)((LPSTR)(pDropFiles)+CurPosition),TEXT(pszTempPath));
    // move the current position beyond the file name copied
    // don't forget the Null terminator (+1)
    CurPosition +=strlen(pszTempPath)+1;
  }
  // final null terminator as per CF_HDROP Format specs.
  ((LPSTR)pDropFiles)[CurPosition]=0;
  GlobalUnlock(hGlobal);
  return hGlobal;
}

This might be of some help

0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
I'll give that a shot.  Thanks.
0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
Didn't work.  I'm begining to wonder if there's isn't something wrong with how I set up my project.  Does it have to be an "ole server" to work?  Is there any check box or anything that I'm missing?  Could you e-mail me the source for that whole project rhamilto@geocites.com?
0
 
LVL 1

Author Comment

by:ElmerFud
Comment Utility
I though yuo'd be glad to know that I got it to work.  :)  You need to make this call beforee doig any OLE stuff:

      OleInitialize(NULL);

and this call when you're done:

      OleUninitialize();

Silly me.  Anyway, thank you for your time.
-Elmer
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Aha .. forgot about that .. sorry I've been asleep.  I live in Australia .. so I sleep while you work [actually, sometimes I sleep while _I_ work :-)].

Glad you've got it going.

I'd be very interested to see the code you ended up with, if you wouldn't mind emailing me at roger.onslow@compsys.com.au

Thanks

0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

763 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

8 Experts available now in Live!

Get 1:1 Help Now